Upgrade phpCAS 0.7
authorRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Wed, 5 Mar 2014 10:39:44 +0000 (11:39 +0100)
committerRadek Czajka <radekczajka@nowoczesnapolska.org.pl>
Wed, 5 Mar 2014 10:39:44 +0000 (11:39 +0100)
86 files changed:
CAS/CAS.php
CAS/CAS/AuthenticationException.php [new file with mode: 0644]
CAS/CAS/Autoload.php [new file with mode: 0644]
CAS/CAS/Client.php [new file with mode: 0644]
CAS/CAS/CookieJar.php [new file with mode: 0644]
CAS/CAS/Exception.php [new file with mode: 0644]
CAS/CAS/GracefullTerminationException.php [new file with mode: 0644]
CAS/CAS/InvalidArgumentException.php [new file with mode: 0644]
CAS/CAS/Languages/Catalan.php [new file with mode: 0644]
CAS/CAS/Languages/English.php [new file with mode: 0644]
CAS/CAS/Languages/French.php [new file with mode: 0644]
CAS/CAS/Languages/German.php [new file with mode: 0644]
CAS/CAS/Languages/Greek.php [new file with mode: 0644]
CAS/CAS/Languages/Japanese.php [new file with mode: 0644]
CAS/CAS/Languages/LanguageInterface.php [new file with mode: 0644]
CAS/CAS/Languages/Spanish.php [new file with mode: 0644]
CAS/CAS/OutOfSequenceException.php [new file with mode: 0644]
CAS/CAS/PGTStorage/AbstractStorage.php [new file with mode: 0644]
CAS/CAS/PGTStorage/Db.php [new file with mode: 0644]
CAS/CAS/PGTStorage/File.php [new file with mode: 0644]
CAS/CAS/PGTStorage/pgt-file.php [deleted file]
CAS/CAS/PGTStorage/pgt-main.php [deleted file]
CAS/CAS/ProxiedService.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Abstract.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Exception.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Http.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Http/Abstract.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Http/Get.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Http/Post.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Imap.php [new file with mode: 0644]
CAS/CAS/ProxiedService/Testable.php [new file with mode: 0644]
CAS/CAS/ProxyChain.php [new file with mode: 0644]
CAS/CAS/ProxyChain/AllowedList.php [new file with mode: 0644]
CAS/CAS/ProxyChain/Any.php [new file with mode: 0644]
CAS/CAS/ProxyChain/Interface.php [new file with mode: 0644]
CAS/CAS/ProxyChain/Trusted.php [new file with mode: 0644]
CAS/CAS/ProxyTicketException.php [new file with mode: 0644]
CAS/CAS/Request/AbstractRequest.php [new file with mode: 0644]
CAS/CAS/Request/CurlMultiRequest.php [new file with mode: 0644]
CAS/CAS/Request/CurlRequest.php [new file with mode: 0644]
CAS/CAS/Request/Exception.php [new file with mode: 0644]
CAS/CAS/Request/MultiRequestInterface.php [new file with mode: 0644]
CAS/CAS/Request/RequestInterface.php [new file with mode: 0644]
CAS/CAS/client.php [deleted file]
CAS/CAS/domxml-php4-to-php5.php [deleted file]
CAS/CAS/languages/catalan.php [deleted file]
CAS/CAS/languages/english.php [deleted file]
CAS/CAS/languages/french.php [deleted file]
CAS/CAS/languages/german.php [deleted file]
CAS/CAS/languages/greek.php [deleted file]
CAS/CAS/languages/japanese.php [deleted file]
CAS/CAS/languages/languages.php [deleted file]
CAS/CAS/languages/spanish.php [deleted file]
CAS/LICENSE [new file with mode: 0644]
CAS/NOTICE [new file with mode: 0644]
CAS/README.md [new file with mode: 0644]
CAS/docs/Building [new file with mode: 0644]
CAS/docs/ChangeLog [new file with mode: 0644]
CAS/docs/Upgrading [new file with mode: 0644]
CAS/docs/examples/config.example.php [new file with mode: 0644]
CAS/docs/examples/create_pgt_storage_db_table.php [new file with mode: 0644]
CAS/docs/examples/example.css [new file with mode: 0644]
CAS/docs/examples/example_advanced_saml11.php [new file with mode: 0644]
CAS/docs/examples/example_custom_urls.php [new file with mode: 0644]
CAS/docs/examples/example_gateway.php [new file with mode: 0644]
CAS/docs/examples/example_html.php [new file with mode: 0644]
CAS/docs/examples/example_lang.php [new file with mode: 0644]
CAS/docs/examples/example_logout.php [new file with mode: 0644]
CAS/docs/examples/example_no_ssl_cn_validation.php [new file with mode: 0644]
CAS/docs/examples/example_pgt_storage_db.php [new file with mode: 0644]
CAS/docs/examples/example_pgt_storage_file.php [new file with mode: 0644]
CAS/docs/examples/example_proxy_GET.php [new file with mode: 0644]
CAS/docs/examples/example_proxy_POST.php [new file with mode: 0644]
CAS/docs/examples/example_proxy_rebroadcast.php [new file with mode: 0644]
CAS/docs/examples/example_proxy_serviceWeb.php [new file with mode: 0644]
CAS/docs/examples/example_proxy_serviceWeb_chaining.php [new file with mode: 0644]
CAS/docs/examples/example_service.php [new file with mode: 0644]
CAS/docs/examples/example_service_POST.php [new file with mode: 0644]
CAS/docs/examples/example_service_that_proxies.php [new file with mode: 0644]
CAS/docs/examples/example_simple.php [new file with mode: 0644]
CAS/docs/examples/script_info.php [new file with mode: 0644]
CAS/docs/images/esup-portail.png [new file with mode: 0644]
CAS/docs/images/jasig.png [new file with mode: 0644]
CAS/docs/images/phpcas.png [new file with mode: 0644]
CAS/docs/index.html [new file with mode: 0644]
CHANGELOG

index e6bae3f..6efafce 100644 (file)
-<?php\r
-\r
-/*\r
- * Copyright © 2003-2010, The ESUP-Portail consortium & the JA-SIG Collaborative.\r
- * All rights reserved.\r
- * \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are met:\r
- * \r
- *     * Redistributions of source code must retain the above copyright notice,\r
- *       this list of conditions and the following disclaimer.\r
- *     * Redistributions in binary form must reproduce the above copyright notice,\r
- *       this list of conditions and the following disclaimer in the documentation\r
- *       and/or other materials provided with the distribution.\r
- *     * Neither the name of the ESUP-Portail consortium & the JA-SIG\r
- *       Collaborative nor the names of its contributors may be used to endorse or\r
- *       promote products derived from this software without specific prior\r
- *       written permission.\r
-\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- */\r
-\r
-//\r
-// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI'] in IIS\r
-//\r
-if (!isset($_SERVER['REQUEST_URI'])) {\r
-       $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];\r
-}\r
-\r
-//\r
-// another one by Vangelis Haniotakis also to make phpCAS work with PHP5\r
-//\r
-if (version_compare(PHP_VERSION, '5', '>=') && !(function_exists('domxml_new_doc'))) {\r
-       require_once (dirname(__FILE__) . '/CAS/domxml-php4-to-php5.php');\r
-}\r
-\r
-/**\r
- * @file CAS/CAS.php\r
- * Interface class of the phpCAS library\r
- *\r
- * @ingroup public\r
- */\r
-\r
-// ########################################################################\r
-//  CONSTANTS\r
-// ########################################################################\r
-\r
-// ------------------------------------------------------------------------\r
-//  CAS VERSIONS\r
-// ------------------------------------------------------------------------\r
-\r
-/**\r
- * phpCAS version. accessible for the user by phpCAS::getVersion().\r
- */\r
-define('PHPCAS_VERSION', '1.1.3');\r
-\r
-// ------------------------------------------------------------------------\r
-//  CAS VERSIONS\r
-// ------------------------------------------------------------------------\r
-/**\r
- * @addtogroup public\r
- * @{\r
- */\r
-\r
-/**\r
- * CAS version 1.0\r
- */\r
-define("CAS_VERSION_1_0", '1.0');\r
-/*!\r
- * CAS version 2.0\r
- */\r
-define("CAS_VERSION_2_0", '2.0');\r
-\r
-// ------------------------------------------------------------------------\r
-//  SAML defines\r
-// ------------------------------------------------------------------------\r
-\r
-/**\r
- * SAML protocol\r
- */\r
-define("SAML_VERSION_1_1", 'S1');\r
-\r
-/**\r
- * XML header for SAML POST\r
- */\r
-define("SAML_XML_HEADER", '<?xml version="1.0" encoding="UTF-8"?>');\r
-\r
-/**\r
- * SOAP envelope for SAML POST\r
- */\r
-define("SAML_SOAP_ENV", '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>');\r
-\r
-/**\r
- * SOAP body for SAML POST\r
- */\r
-define("SAML_SOAP_BODY", '<SOAP-ENV:Body>');\r
-\r
-/**\r
- * SAMLP request\r
- */\r
-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">');\r
-define("SAMLP_REQUEST_CLOSE", '</samlp:Request>');\r
-\r
-/**\r
- * SAMLP artifact tag (for the ticket)\r
- */\r
-define("SAML_ASSERTION_ARTIFACT", '<samlp:AssertionArtifact>');\r
-\r
-/**\r
- * SAMLP close\r
- */\r
-define("SAML_ASSERTION_ARTIFACT_CLOSE", '</samlp:AssertionArtifact>');\r
-\r
-/**\r
- * SOAP body close\r
- */\r
-define("SAML_SOAP_BODY_CLOSE", '</SOAP-ENV:Body>');\r
-\r
-/**\r
- * SOAP envelope close\r
- */\r
-define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');\r
-\r
-/**\r
- * SAML Attributes\r
- */\r
-define("SAML_ATTRIBUTES", 'SAMLATTRIBS');\r
-\r
-/** @} */\r
-/**\r
- * @addtogroup publicPGTStorage\r
- * @{\r
- */\r
-// ------------------------------------------------------------------------\r
-//  FILE PGT STORAGE\r
-// ------------------------------------------------------------------------\r
-/**\r
- * Default path used when storing PGT's to file\r
- */\r
-define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", '/tmp');\r
-/**\r
- * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files\r
- */\r
-define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN", 'plain');\r
-/**\r
- * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files\r
- */\r
-define("CAS_PGT_STORAGE_FILE_FORMAT_XML", 'xml');\r
-/**\r
- * Default format used when storing PGT's to file\r
- */\r
-define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT", CAS_PGT_STORAGE_FILE_FORMAT_PLAIN);\r
-/** @} */\r
-// ------------------------------------------------------------------------\r
-// SERVICE ACCESS ERRORS\r
-// ------------------------------------------------------------------------\r
-/**\r
- * @addtogroup publicServices\r
- * @{\r
- */\r
-\r
-/**\r
- * phpCAS::service() error code on success\r
- */\r
-define("PHPCAS_SERVICE_OK", 0);\r
-/**\r
- * phpCAS::service() error code when the PT could not retrieve because\r
- * the CAS server did not respond.\r
- */\r
-define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1);\r
-/**\r
- * phpCAS::service() error code when the PT could not retrieve because\r
- * the response of the CAS server was ill-formed.\r
- */\r
-define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2);\r
-/**\r
- * phpCAS::service() error code when the PT could not retrieve because\r
- * the CAS server did not want to.\r
- */\r
-define("PHPCAS_SERVICE_PT_FAILURE", 3);\r
-/**\r
- * phpCAS::service() error code when the service was not available.\r
- */\r
-define("PHPCAS_SERVICE_NOT AVAILABLE", 4);\r
-\r
-/** @} */\r
-// ------------------------------------------------------------------------\r
-//  LANGUAGES\r
-// ------------------------------------------------------------------------\r
-/**\r
- * @addtogroup publicLang\r
- * @{\r
- */\r
-\r
-define("PHPCAS_LANG_ENGLISH", 'english');\r
-define("PHPCAS_LANG_FRENCH", 'french');\r
-define("PHPCAS_LANG_GREEK", 'greek');\r
-define("PHPCAS_LANG_GERMAN", 'german');\r
-define("PHPCAS_LANG_JAPANESE", 'japanese');\r
-define("PHPCAS_LANG_SPANISH", 'spanish');\r
-define("PHPCAS_LANG_CATALAN", 'catalan');\r
-\r
-/** @} */\r
-\r
-/**\r
- * @addtogroup internalLang\r
- * @{\r
- */\r
-\r
-/**\r
- * phpCAS default language (when phpCAS::setLang() is not used)\r
- */\r
-define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);\r
-\r
-/** @} */\r
-// ------------------------------------------------------------------------\r
-//  DEBUG\r
-// ------------------------------------------------------------------------\r
-/**\r
- * @addtogroup publicDebug\r
- * @{\r
- */\r
-\r
-/**\r
- * The default directory for the debug file under Unix.\r
- */\r
-define('DEFAULT_DEBUG_DIR', '/tmp/');\r
-\r
-/** @} */\r
-// ------------------------------------------------------------------------\r
-//  MISC\r
-// ------------------------------------------------------------------------\r
-/**\r
- * @addtogroup internalMisc\r
- * @{\r
- */\r
-\r
-/**\r
- * This global variable is used by the interface class phpCAS.\r
- *\r
- * @hideinitializer\r
- */\r
-$GLOBALS['PHPCAS_CLIENT'] = null;\r
-\r
-/**\r
- * This global variable is used to store where the initializer is called from \r
- * (to print a comprehensive error in case of multiple calls).\r
- *\r
- * @hideinitializer\r
- */\r
-$GLOBALS['PHPCAS_INIT_CALL'] = array (\r
-       'done' => FALSE,\r
-       'file' => '?',\r
-       'line' => -1,\r
-       'method' => '?'\r
-);\r
-\r
-/**\r
- * This global variable is used to store where the method checking\r
- * the authentication is called from (to print comprehensive errors)\r
- *\r
- * @hideinitializer\r
- */\r
-$GLOBALS['PHPCAS_AUTH_CHECK_CALL'] = array (\r
-       'done' => FALSE,\r
-       'file' => '?',\r
-       'line' => -1,\r
-       'method' => '?',\r
-       'result' => FALSE\r
-);\r
-\r
-/**\r
- * This global variable is used to store phpCAS debug mode.\r
- *\r
- * @hideinitializer\r
- */\r
-$GLOBALS['PHPCAS_DEBUG'] = array (\r
-       'filename' => FALSE,\r
-       'indent' => 0,\r
-       'unique_id' => ''\r
-);\r
-\r
-/** @} */\r
-\r
-// ########################################################################\r
-//  CLIENT CLASS\r
-// ########################################################################\r
-\r
-// include client class\r
-include_once (dirname(__FILE__) . '/CAS/client.php');\r
-\r
-// ########################################################################\r
-//  INTERFACE CLASS\r
-// ########################################################################\r
-\r
-/**\r
- * @class phpCAS\r
- * The phpCAS class is a simple container for the phpCAS library. It provides CAS\r
- * authentication for web applications written in PHP.\r
- *\r
- * @ingroup public\r
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- *\r
- * \internal All its methods access the same object ($PHPCAS_CLIENT, declared \r
- * at the end of CAS/client.php).\r
- */\r
-\r
-class phpCAS {\r
-\r
-       // ########################################################################\r
-       //  INITIALIZATION\r
-       // ########################################################################\r
-\r
-       /**\r
-        * @addtogroup publicInit\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * phpCAS client initializer.\r
-        * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be\r
-        * called, only once, and before all other methods (except phpCAS::getVersion()\r
-        * and phpCAS::setDebug()).\r
-        *\r
-        * @param $server_version the version of the CAS server\r
-        * @param $server_hostname the hostname of the CAS server\r
-        * @param $server_port the port the CAS server is running on\r
-        * @param $server_uri the URI the CAS server is responding on\r
-        * @param $start_session Have phpCAS start PHP sessions (default true)\r
-        *\r
-        * @return a newly created CASClient object\r
-        */\r
-       function client($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
-               global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error($PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . $PHPCAS_INIT_CALL['file'] . ':' . $PHPCAS_INIT_CALL['line'] . ')');\r
-               }\r
-               if (gettype($server_version) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');\r
-               }\r
-               if (gettype($server_hostname) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');\r
-               }\r
-               if (gettype($server_port) != 'integer') {\r
-                       phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');\r
-               }\r
-               if (gettype($server_uri) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');\r
-               }\r
-\r
-               // store where the initializer is called from\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_INIT_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__\r
-               );\r
-\r
-               // initialize the global object $PHPCAS_CLIENT\r
-               $PHPCAS_CLIENT = new CASClient($server_version, FALSE /*proxy*/\r
-               , $server_hostname, $server_port, $server_uri, $start_session);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * phpCAS proxy initializer.\r
-        * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be\r
-        * called, only once, and before all other methods (except phpCAS::getVersion()\r
-        * and phpCAS::setDebug()).\r
-        *\r
-        * @param $server_version the version of the CAS server\r
-        * @param $server_hostname the hostname of the CAS server\r
-        * @param $server_port the port the CAS server is running on\r
-        * @param $server_uri the URI the CAS server is responding on\r
-        * @param $start_session Have phpCAS start PHP sessions (default true)\r
-        *\r
-        * @return a newly created CASClient object\r
-        */\r
-       function proxy($server_version, $server_hostname, $server_port, $server_uri, $start_session = true) {\r
-               global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error($PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . $PHPCAS_INIT_CALL['file'] . ':' . $PHPCAS_INIT_CALL['line'] . ')');\r
-               }\r
-               if (gettype($server_version) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');\r
-               }\r
-               if (gettype($server_hostname) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');\r
-               }\r
-               if (gettype($server_port) != 'integer') {\r
-                       phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');\r
-               }\r
-               if (gettype($server_uri) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');\r
-               }\r
-\r
-               // store where the initialzer is called from\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_INIT_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__\r
-               );\r
-\r
-               // initialize the global object $PHPCAS_CLIENT\r
-               $PHPCAS_CLIENT = new CASClient($server_version, TRUE /*proxy*/\r
-               , $server_hostname, $server_port, $server_uri, $start_session);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  DEBUGGING\r
-       // ########################################################################\r
-\r
-       /**\r
-        * @addtogroup publicDebug\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * Set/unset debug mode\r
-        *\r
-        * @param $filename the name of the file used for logging, or FALSE to stop debugging.\r
-        */\r
-       function setDebug($filename = '') {\r
-               global $PHPCAS_DEBUG;\r
-\r
-               if ($filename != FALSE && gettype($filename) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $dbg (should be FALSE or the name of the log file)');\r
-               }\r
-\r
-               if (empty ($filename)) {\r
-                       if (preg_match('/^Win.*/', getenv('OS'))) {\r
-                               if (isset ($_ENV['TMP'])) {\r
-                                       $debugDir = $_ENV['TMP'] . '/';\r
-                               } else\r
-                                       if (isset ($_ENV['TEMP'])) {\r
-                                               $debugDir = $_ENV['TEMP'] . '/';\r
-                                       } else {\r
-                                               $debugDir = '';\r
-                                       }\r
-                       } else {\r
-                               $debugDir = DEFAULT_DEBUG_DIR;\r
-                       }\r
-                       $filename = $debugDir . 'phpCAS.log';\r
-               }\r
-\r
-               if (empty ($PHPCAS_DEBUG['unique_id'])) {\r
-                       $PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);\r
-               }\r
-\r
-               $PHPCAS_DEBUG['filename'] = $filename;\r
-\r
-               phpCAS :: trace('START phpCAS-' . PHPCAS_VERSION . ' ******************');\r
-       }\r
-\r
-       /** @} */\r
-       /**\r
-        * @addtogroup internalDebug\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method is a wrapper for debug_backtrace() that is not available \r
-        * in all PHP versions (>= 4.3.0 only)\r
-        */\r
-       function backtrace() {\r
-               if (function_exists('debug_backtrace')) {\r
-                       return debug_backtrace();\r
-               } else {\r
-                       // poor man's hack ... but it does work ...\r
-                       return array ();\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Logs a string in debug mode.\r
-        *\r
-        * @param $str the string to write\r
-        *\r
-        * @private\r
-        */\r
-       function log($str) {\r
-               $indent_str = ".";\r
-               global $PHPCAS_DEBUG;\r
-\r
-               if ($PHPCAS_DEBUG['filename']) {\r
-                       for ($i = 0; $i < $PHPCAS_DEBUG['indent']; $i++) {\r
-                               $indent_str .= '|    ';\r
-                       }\r
-                       error_log($PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str . "\n", 3, $PHPCAS_DEBUG['filename']);\r
-               }\r
-\r
-       }\r
-\r
-       /**\r
-        * This method is used by interface methods to print an error and where the function\r
-        * was originally called from.\r
-        *\r
-        * @param $msg the message to print\r
-        *\r
-        * @private\r
-        */\r
-       function error($msg) {\r
-               $dbg = phpCAS :: backtrace();\r
-               $function = '?';\r
-               $file = '?';\r
-               $line = '?';\r
-               if (is_array($dbg)) {\r
-                       for ($i = 1; $i < sizeof($dbg); $i++) {\r
-                               if (is_array($dbg[$i])) {\r
-                                       if ($dbg[$i]['class'] == __CLASS__) {\r
-                                               $function = $dbg[$i]['function'];\r
-                                               $file = $dbg[$i]['file'];\r
-                                               $line = $dbg[$i]['line'];\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-               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";\r
-               phpCAS :: trace($msg);\r
-               phpCAS :: traceExit();\r
-               exit ();\r
-       }\r
-\r
-       /**\r
-        * This method is used to log something in debug mode.\r
-        */\r
-       function trace($str) {\r
-               $dbg = phpCAS :: backtrace();\r
-               phpCAS :: log($str . ' [' . basename($dbg[1]['file']) . ':' . $dbg[1]['line'] . ']');\r
-       }\r
-\r
-       /**\r
-        * This method is used to indicate the start of the execution of a function in debug mode.\r
-        */\r
-       function traceBegin() {\r
-               global $PHPCAS_DEBUG;\r
-\r
-               $dbg = phpCAS :: backtrace();\r
-               $str = '=> ';\r
-               if (!empty ($dbg[2]['class'])) {\r
-                       $str .= $dbg[2]['class'] . '::';\r
-               }\r
-               $str .= $dbg[2]['function'] . '(';\r
-               if (is_array($dbg[2]['args'])) {\r
-                       foreach ($dbg[2]['args'] as $index => $arg) {\r
-                               if ($index != 0) {\r
-                                       $str .= ', ';\r
-                               }\r
-                               $str .= str_replace("\n", "", var_export($arg, TRUE));\r
-                       }\r
-               }\r
-               $str .= ') [' . basename($dbg[2]['file']) . ':' . $dbg[2]['line'] . ']';\r
-               phpCAS :: log($str);\r
-               $PHPCAS_DEBUG['indent']++;\r
-       }\r
-\r
-       /**\r
-        * This method is used to indicate the end of the execution of a function in debug mode.\r
-        *\r
-        * @param $res the result of the function\r
-        */\r
-       function traceEnd($res = '') {\r
-               global $PHPCAS_DEBUG;\r
-\r
-               $PHPCAS_DEBUG['indent']--;\r
-               $dbg = phpCAS :: backtrace();\r
-               $str = '';\r
-               $str .= '<= ' . str_replace("\n", "", var_export($res, TRUE));\r
-               phpCAS :: log($str);\r
-       }\r
-\r
-       /**\r
-        * This method is used to indicate the end of the execution of the program\r
-        */\r
-       function traceExit() {\r
-               global $PHPCAS_DEBUG;\r
-\r
-               phpCAS :: log('exit()');\r
-               while ($PHPCAS_DEBUG['indent'] > 0) {\r
-                       phpCAS :: log('-');\r
-                       $PHPCAS_DEBUG['indent']--;\r
-               }\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  INTERNATIONALIZATION\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup publicLang\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method is used to set the language used by phpCAS. \r
-        * @note Can be called only once.\r
-        *\r
-        * @param $lang a string representing the language.\r
-        *\r
-        * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH\r
-        */\r
-       function setLang($lang) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($lang) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $lang (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setLang($lang);\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  VERSION\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup public\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method returns the phpCAS version.\r
-        *\r
-        * @return the phpCAS version.\r
-        */\r
-       function getVersion() {\r
-               return PHPCAS_VERSION;\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  HTML OUTPUT\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup publicOutput\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method sets the HTML header used for all outputs.\r
-        *\r
-        * @param $header the HTML header.\r
-        */\r
-       function setHTMLHeader($header) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($header) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $header (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setHTMLHeader($header);\r
-       }\r
-\r
-       /**\r
-        * This method sets the HTML footer used for all outputs.\r
-        *\r
-        * @param $footer the HTML footer.\r
-        */\r
-       function setHTMLFooter($footer) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($footer) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $footer (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setHTMLFooter($footer);\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  PGT STORAGE\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup publicPGTStorage\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method is used to tell phpCAS to store the response of the\r
-        * CAS server to PGT requests onto the filesystem. \r
-        *\r
-        * @param $format the format used to store the PGT's (`plain' and `xml' allowed)\r
-        * @param $path the path where the PGT's should be stored\r
-        */\r
-       function setPGTStorageFile($format = '', $path = '') {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_CLIENT->isProxy()) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if ($PHPCAS_AUTH_CHECK_CALL['done']) {\r
-                       phpCAS :: error('this method should only be called before ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() (called at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ')');\r
-               }\r
-               if (gettype($format) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $format (should be `string\')');\r
-               }\r
-               if (gettype($path) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $format (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setPGTStorageFile($format, $path);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       // ACCESS TO EXTERNAL SERVICES\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup publicServices\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * This method is used to access an HTTP[S] service.\r
-        * \r
-        * @param $url the service to access.\r
-        * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on\r
-        * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,\r
-        * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.\r
-        * @param $output the output of the service (also used to give an error\r
-        * message on failure).\r
-        *\r
-        * @return TRUE on success, FALSE otherwise (in this later case, $err_code\r
-        * gives the reason why it failed and $output contains an error message).\r
-        */\r
-       function serviceWeb($url, & $err_code, & $output) {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_CLIENT->isProxy()) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['done']) {\r
-                       phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['result']) {\r
-                       phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-\r
-               $res = $PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);\r
-\r
-               phpCAS :: traceEnd($res);\r
-               return $res;\r
-       }\r
-\r
-       /**\r
-        * This method is used to access an IMAP/POP3/NNTP service.\r
-        * \r
-        * @param $url a string giving the URL of the service, including the mailing box\r
-        * for IMAP URLs, as accepted by imap_open().\r
-        * @param $service a string giving for CAS retrieve Proxy ticket\r
-        * @param $flags options given to imap_open().\r
-        * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on\r
-        * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,\r
-        * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.\r
-        * @param $err_msg an error message on failure\r
-        * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL\r
-        * on success, FALSE on error).\r
-        *\r
-        * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code\r
-        * gives the reason why it failed and $err_msg contains an error message).\r
-        */\r
-       function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_CLIENT->isProxy()) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['done']) {\r
-                       phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['result']) {\r
-                       phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-\r
-               if (gettype($flags) != 'integer') {\r
-                       phpCAS :: error('type mismatched for parameter $flags (should be `integer\')');\r
-               }\r
-\r
-               $res = $PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);\r
-\r
-               phpCAS :: traceEnd($res);\r
-               return $res;\r
-       }\r
-\r
-       /** @} */\r
-       // ########################################################################\r
-       //  AUTHENTICATION\r
-       // ########################################################################\r
-       /**\r
-        * @addtogroup publicAuth\r
-        * @{\r
-        */\r
-\r
-       /**\r
-        * Set the times authentication will be cached before really accessing the CAS server in gateway mode: \r
-        * - -1: check only once, and then never again (until you pree login)\r
-        * - 0: always check\r
-        * - n: check every "n" time\r
-        *\r
-        * @param $n an integer.\r
-        */\r
-       function setCacheTimesForAuthRecheck($n) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($n) != 'integer') {\r
-                       phpCAS :: error('type mismatched for parameter $header (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);\r
-       }\r
-\r
-       /**\r
-        * This method is called to check if the user is authenticated (use the gateway feature).\r
-        * @return TRUE when the user is authenticated; otherwise FALSE.\r
-        */\r
-       function checkAuthentication() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-\r
-               $auth = $PHPCAS_CLIENT->checkAuthentication();\r
-\r
-               // store where the authentication has been checked and the result\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_AUTH_CHECK_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__,\r
-                       'result' => $auth\r
-               );\r
-               phpCAS :: traceEnd($auth);\r
-               return $auth;\r
-       }\r
-\r
-       /**\r
-        * This method is called to force authentication if the user was not already \r
-        * authenticated. If the user is not authenticated, halt by redirecting to \r
-        * the CAS server.\r
-        */\r
-       function forceAuthentication() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-\r
-               $auth = $PHPCAS_CLIENT->forceAuthentication();\r
-\r
-               // store where the authentication has been checked and the result\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_AUTH_CHECK_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__,\r
-                       'result' => $auth\r
-               );\r
-\r
-               if (!$auth) {\r
-                       phpCAS :: trace('user is not authenticated, redirecting to the CAS server');\r
-                       $PHPCAS_CLIENT->forceAuthentication();\r
-               } else {\r
-                       phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)');\r
-               }\r
-\r
-               phpCAS :: traceEnd();\r
-               return $auth;\r
-       }\r
-\r
-       /**\r
-        * This method is called to renew the authentication.\r
-        **/\r
-       function renewAuthentication() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-\r
-               // store where the authentication has been checked and the result\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_AUTH_CHECK_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__,\r
-                       'result' => $auth\r
-               );\r
-\r
-               $PHPCAS_CLIENT->renewAuthentication();\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method has been left from version 0.4.1 for compatibility reasons.\r
-        */\r
-       function authenticate() {\r
-               phpCAS :: error('this method is deprecated. You should use ' . __CLASS__ . '::forceAuthentication() instead');\r
-       }\r
-\r
-       /**\r
-        * This method is called to check if the user is authenticated (previously or by\r
-        * tickets given in the URL).\r
-        *\r
-        * @return TRUE when the user is authenticated.\r
-        */\r
-       function isAuthenticated() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-\r
-               // call the isAuthenticated method of the global $PHPCAS_CLIENT object\r
-               $auth = $PHPCAS_CLIENT->isAuthenticated();\r
-\r
-               // store where the authentication has been checked and the result\r
-               $dbg = phpCAS :: backtrace();\r
-               $PHPCAS_AUTH_CHECK_CALL = array (\r
-                       'done' => TRUE,\r
-                       'file' => $dbg[0]['file'],\r
-                       'line' => $dbg[0]['line'],\r
-                       'method' => __CLASS__ . '::' . __FUNCTION__,\r
-                       'result' => $auth\r
-               );\r
-               phpCAS :: traceEnd($auth);\r
-               return $auth;\r
-       }\r
-\r
-       /**\r
-        * Checks whether authenticated based on $_SESSION. Useful to avoid\r
-        * server calls.\r
-        * @return true if authenticated, false otherwise.\r
-        * @since 0.4.22 by Brendan Arnold\r
-        */\r
-       function isSessionAuthenticated() {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               return ($PHPCAS_CLIENT->isSessionAuthenticated());\r
-       }\r
-\r
-       /**\r
-        * This method returns the CAS user's login name.\r
-        * @warning should not be called only after phpCAS::forceAuthentication()\r
-        * or phpCAS::checkAuthentication().\r
-        *\r
-        * @return the login name of the authenticated user\r
-        */\r
-       function getUser() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['done']) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['result']) {\r
-                       phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE');\r
-               }\r
-               return $PHPCAS_CLIENT->getUser();\r
-       }\r
-\r
-       /**\r
-        * This method returns the CAS user's login name.\r
-        * @warning should not be called only after phpCAS::forceAuthentication()\r
-        * or phpCAS::checkAuthentication().\r
-        *\r
-        * @return the login name of the authenticated user\r
-        */\r
-       function getAttributes() {\r
-               global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['done']) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');\r
-               }\r
-               if (!$PHPCAS_AUTH_CHECK_CALL['result']) {\r
-                       phpCAS :: error('authentication was checked (by ' . $PHPCAS_AUTH_CHECK_CALL['method'] . '() at ' . $PHPCAS_AUTH_CHECK_CALL['file'] . ':' . $PHPCAS_AUTH_CHECK_CALL['line'] . ') but the method returned FALSE');\r
-               }\r
-               return $PHPCAS_CLIENT->getAttributes();\r
-       }\r
-       /**\r
-        * Handle logout requests.\r
-        */\r
-       function handleLogoutRequests($check_client = true, $allowed_clients = false) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               return ($PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));\r
-       }\r
-\r
-       /**\r
-        * This method returns the URL to be used to login.\r
-        * or phpCAS::isAuthenticated().\r
-        *\r
-        * @return the login name of the authenticated user\r
-        */\r
-       function getServerLoginURL() {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               return $PHPCAS_CLIENT->getServerLoginURL();\r
-       }\r
-\r
-       /**\r
-        * Set the login URL of the CAS server.\r
-        * @param $url the login URL\r
-        * @since 0.4.21 by Wyman Chan\r
-        */\r
-       function setServerLoginURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after\r
-                                                       ' . __CLASS__ . '::client()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be\r
-                                               `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setServerLoginURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the serviceValidate URL of the CAS server.\r
-        * Used only in CAS 1.0 validations\r
-        * @param $url the serviceValidate URL\r
-        * @since 1.1.0 by Joachim Fritschi\r
-        */\r
-       function setServerServiceValidateURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after\r
-                                                       ' . __CLASS__ . '::client()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be\r
-                                               `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setServerServiceValidateURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the proxyValidate URL of the CAS server.\r
-        * Used for all CAS 2.0 validations\r
-        * @param $url the proxyValidate URL\r
-        * @since 1.1.0 by Joachim Fritschi\r
-        */\r
-       function setServerProxyValidateURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after\r
-                                                       ' . __CLASS__ . '::client()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be\r
-                                               `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setServerProxyValidateURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the samlValidate URL of the CAS server.\r
-        * @param $url the samlValidate URL\r
-        * @since 1.1.0 by Joachim Fritschi\r
-        */\r
-       function setServerSamlValidateURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after\r
-                                                       ' . __CLASS__ . '::client()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be\r
-                                               `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setServerSamlValidateURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method returns the URL to be used to login.\r
-        * or phpCAS::isAuthenticated().\r
-        *\r
-        * @return the login name of the authenticated user\r
-        */\r
-       function getServerLogoutURL() {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');\r
-               }\r
-               return $PHPCAS_CLIENT->getServerLogoutURL();\r
-       }\r
-\r
-       /**\r
-        * Set the logout URL of the CAS server.\r
-        * @param $url the logout URL\r
-        * @since 0.4.21 by Wyman Chan\r
-        */\r
-       function setServerLogoutURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after\r
-                                                       ' . __CLASS__ . '::client()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be\r
-                                               `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setServerLogoutURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method is used to logout from CAS.\r
-        * @params $params an array that contains the optional url and service parameters that will be passed to the CAS server\r
-        * @public\r
-        */\r
-       function logout($params = "") {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               $parsedParams = array ();\r
-               if ($params != "") {\r
-                       if (is_string($params)) {\r
-                               phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead');\r
-                       }\r
-                       if (!is_array($params)) {\r
-                               phpCAS :: error('type mismatched for parameter $params (should be `array\')');\r
-                       }\r
-                       foreach ($params as $key => $value) {\r
-                               if ($key != "service" && $key != "url") {\r
-                                       phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\'');\r
-                               }\r
-                               $parsedParams[$key] = $value;\r
-                       }\r
-               }\r
-               $PHPCAS_CLIENT->logout($parsedParams);\r
-               // never reached\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method is used to logout from CAS. Halts by redirecting to the CAS server.\r
-        * @param $service a URL that will be transmitted to the CAS server\r
-        */\r
-       function logoutWithRedirectService($service) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!is_string($service)) {\r
-                       phpCAS :: error('type mismatched for parameter $service (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->logout(array (\r
-                       "service" => $service\r
-               ));\r
-               // never reached\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method is used to logout from CAS. Halts by redirecting to the CAS server.\r
-        * @param $url a URL that will be transmitted to the CAS server\r
-        */\r
-       function logoutWithUrl($url) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!is_string($url)) {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->logout(array (\r
-                       "url" => $url\r
-               ));\r
-               // never reached\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * This method is used to logout from CAS. Halts by redirecting to the CAS server.\r
-        * @param $service a URL that will be transmitted to the CAS server\r
-        * @param $url a URL that will be transmitted to the CAS server\r
-        */\r
-       function logoutWithRedirectServiceAndUrl($service, $url) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!is_string($service)) {\r
-                       phpCAS :: error('type mismatched for parameter $service (should be `string\')');\r
-               }\r
-               if (!is_string($url)) {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->logout(array (\r
-                       "service" => $service,\r
-                       "url" => $url\r
-               ));\r
-               // never reached\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the fixed URL that will be used by the CAS server to transmit the PGT.\r
-        * When this method is not called, a phpCAS script uses its own URL for the callback.\r
-        *\r
-        * @param $url the URL\r
-        */\r
-       function setFixedCallbackURL($url = '') {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (!$PHPCAS_CLIENT->isProxy()) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setCallbackURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the fixed URL that will be set as the CAS service parameter. When this\r
-        * method is not called, a phpCAS script uses its own URL.\r
-        *\r
-        * @param $url the URL\r
-        */\r
-       function setFixedServiceURL($url) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($url) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $url (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setURL($url);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Get the URL that is set as the CAS service parameter.\r
-        */\r
-       function getServiceURL() {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               return ($PHPCAS_CLIENT->getURL());\r
-       }\r
-\r
-       /**\r
-        * Retrieve a Proxy Ticket from the CAS server.\r
-        */\r
-       function retrievePT($target_service, & $err_code, & $err_msg) {\r
-               global $PHPCAS_CLIENT;\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($target_service) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $target_service(should be `string\')');\r
-               }\r
-               return ($PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));\r
-       }\r
-\r
-       /**\r
-        * Set the certificate of the CAS server.\r
-        *\r
-        * @param $cert the PEM certificate\r
-        */\r
-       function setCasServerCert($cert) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($cert) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $cert (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setCasServerCert($cert);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set the certificate of the CAS server CA.\r
-        *\r
-        * @param $cert the CA certificate\r
-        */\r
-       function setCasServerCACert($cert) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               if (gettype($cert) != 'string') {\r
-                       phpCAS :: error('type mismatched for parameter $cert (should be `string\')');\r
-               }\r
-               $PHPCAS_CLIENT->setCasServerCACert($cert);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /**\r
-        * Set no SSL validation for the CAS server.\r
-        */\r
-       function setNoCasServerValidation() {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               $PHPCAS_CLIENT->setNoCasServerValidation();\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-       /** @} */\r
-\r
-       /**\r
-        * Change CURL options.\r
-        * CURL is used to connect through HTTPS to CAS server\r
-        * @param $key the option key\r
-        * @param $value the value to set\r
-        */\r
-       function setExtraCurlOption($key, $value) {\r
-               global $PHPCAS_CLIENT;\r
-               phpCAS :: traceBegin();\r
-               if (!is_object($PHPCAS_CLIENT)) {\r
-                       phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');\r
-               }\r
-               $PHPCAS_CLIENT->setExtraCurlOption($key, $value);\r
-               phpCAS :: traceEnd();\r
-       }\r
-\r
-}\r
-\r
-// ########################################################################\r
-// DOCUMENTATION\r
-// ########################################################################\r
-\r
-// ########################################################################\r
-//  MAIN PAGE\r
-\r
-/**\r
- * @mainpage\r
- *\r
- * The following pages only show the source documentation.\r
- *\r
- */\r
-\r
-// ########################################################################\r
-//  MODULES DEFINITION\r
-\r
-/** @defgroup public User interface */\r
-\r
-/** @defgroup publicInit Initialization\r
- *  @ingroup public */\r
-\r
-/** @defgroup publicAuth Authentication\r
- *  @ingroup public */\r
-\r
-/** @defgroup publicServices Access to external services\r
- *  @ingroup public */\r
-\r
-/** @defgroup publicConfig Configuration\r
- *  @ingroup public */\r
-\r
-/** @defgroup publicLang Internationalization\r
- *  @ingroup publicConfig */\r
-\r
-/** @defgroup publicOutput HTML output\r
- *  @ingroup publicConfig */\r
-\r
-/** @defgroup publicPGTStorage PGT storage\r
- *  @ingroup publicConfig */\r
-\r
-/** @defgroup publicDebug Debugging\r
- *  @ingroup public */\r
-\r
-/** @defgroup internal Implementation */\r
-\r
-/** @defgroup internalAuthentication Authentication\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalPGTStorage PGT storage\r
- *  @ingroup internalProxy */\r
-\r
-/** @defgroup internalPGTStorageFile PGT storage on the filesystem\r
- *  @ingroup internalPGTStorage */\r
-\r
-/** @defgroup internalCallback Callback from the CAS server\r
- *  @ingroup internalProxy */\r
-\r
-/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets)\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalConfig Configuration\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalOutput HTML output\r
- *  @ingroup internalConfig */\r
-\r
-/** @defgroup internalLang Internationalization\r
- *  @ingroup internalConfig\r
- *\r
- * To add a new language:\r
- * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php\r
- * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php\r
- * - 3. Make the translations\r
- */\r
-\r
-/** @defgroup internalDebug Debugging\r
- *  @ingroup internal */\r
-\r
-/** @defgroup internalMisc Miscellaneous\r
- *  @ingroup internal */\r
-\r
-// ########################################################################\r
-//  EXAMPLES\r
-\r
-/**\r
- * @example example_simple.php\r
- */\r
-/**\r
- * @example example_proxy.php\r
- */\r
-/**\r
- * @example example_proxy2.php\r
- */\r
-/**\r
- * @example example_lang.php\r
- */\r
-/**\r
- * @example example_html.php\r
- */\r
-/**\r
- * @example example_file.php\r
- */\r
-/**\r
- * @example example_db.php\r
- */\r
-/**\r
- * @example example_service.php\r
- */\r
-/**\r
- * @example example_session_proxy.php\r
- */\r
-/**\r
- * @example example_session_service.php\r
- */\r
-/**\r
- * @example example_gateway.php\r
- */\r
-/**\r
- * @example example_custom_urls.php\r
- */\r
-?>\r
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ *
+ * Interface class of the phpCAS library
+ * PHP Version 5
+ *
+ * @file     CAS/CAS.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ * @ingroup public
+ */
+
+
+//
+// hack by Vangelis Haniotakis to handle the absence of $_SERVER['REQUEST_URI']
+// in IIS
+//
+if (php_sapi_name() != 'cli') {
+    if (!isset($_SERVER['REQUEST_URI'])) {
+        $_SERVER['REQUEST_URI'] = $_SERVER['SCRIPT_NAME'] . '?' . $_SERVER['QUERY_STRING'];
+    }
+}
+
+// Add a E_USER_DEPRECATED for php versions <= 5.2
+if (!defined('E_USER_DEPRECATED')) {
+    define('E_USER_DEPRECATED', E_USER_NOTICE);
+}
+
+
+// ########################################################################
+//  CONSTANTS
+// ########################################################################
+
+// ------------------------------------------------------------------------
+//  CAS VERSIONS
+// ------------------------------------------------------------------------
+
+/**
+ * phpCAS version. accessible for the user by phpCAS::getVersion().
+ */
+define('PHPCAS_VERSION', '1.3.2');
+
+/**
+ * @addtogroup public
+ * @{
+ */
+
+/**
+ * CAS version 1.0
+ */
+define("CAS_VERSION_1_0", '1.0');
+/*!
+ * CAS version 2.0
+*/
+define("CAS_VERSION_2_0", '2.0');
+
+// ------------------------------------------------------------------------
+//  SAML defines
+// ------------------------------------------------------------------------
+
+/**
+ * SAML protocol
+ */
+define("SAML_VERSION_1_1", 'S1');
+
+/**
+ * XML header for SAML POST
+ */
+define("SAML_XML_HEADER", '<?xml version="1.0" encoding="UTF-8"?>');
+
+/**
+ * SOAP envelope for SAML POST
+ */
+define("SAML_SOAP_ENV", '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Header/>');
+
+/**
+ * SOAP body for SAML POST
+ */
+define("SAML_SOAP_BODY", '<SOAP-ENV:Body>');
+
+/**
+ * SAMLP request
+ */
+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">');
+define("SAMLP_REQUEST_CLOSE", '</samlp:Request>');
+
+/**
+ * SAMLP artifact tag (for the ticket)
+ */
+define("SAML_ASSERTION_ARTIFACT", '<samlp:AssertionArtifact>');
+
+/**
+ * SAMLP close
+ */
+define("SAML_ASSERTION_ARTIFACT_CLOSE", '</samlp:AssertionArtifact>');
+
+/**
+ * SOAP body close
+ */
+define("SAML_SOAP_BODY_CLOSE", '</SOAP-ENV:Body>');
+
+/**
+ * SOAP envelope close
+ */
+define("SAML_SOAP_ENV_CLOSE", '</SOAP-ENV:Envelope>');
+
+/**
+ * SAML Attributes
+ */
+define("SAML_ATTRIBUTES", 'SAMLATTRIBS');
+
+/** @} */
+/**
+ * @addtogroup publicPGTStorage
+ * @{
+ */
+// ------------------------------------------------------------------------
+//  FILE PGT STORAGE
+// ------------------------------------------------------------------------
+/**
+ * Default path used when storing PGT's to file
+ */
+define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path());
+/** @} */
+// ------------------------------------------------------------------------
+// SERVICE ACCESS ERRORS
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicServices
+ * @{
+ */
+
+/**
+ * phpCAS::service() error code on success
+ */
+define("PHPCAS_SERVICE_OK", 0);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not respond.
+ */
+define("PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE", 1);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the response of the CAS server was ill-formed.
+ */
+define("PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE", 2);
+/**
+ * phpCAS::service() error code when the PT could not retrieve because
+ * the CAS server did not want to.
+ */
+define("PHPCAS_SERVICE_PT_FAILURE", 3);
+/**
+ * phpCAS::service() error code when the service was not available.
+ */
+define("PHPCAS_SERVICE_NOT_AVAILABLE", 4);
+
+// ------------------------------------------------------------------------
+// SERVICE TYPES
+// ------------------------------------------------------------------------
+/**
+ * phpCAS::getProxiedService() type for HTTP GET
+ */
+define("PHPCAS_PROXIED_SERVICE_HTTP_GET", 'CAS_ProxiedService_Http_Get');
+/**
+ * phpCAS::getProxiedService() type for HTTP POST
+ */
+define("PHPCAS_PROXIED_SERVICE_HTTP_POST", 'CAS_ProxiedService_Http_Post');
+/**
+ * phpCAS::getProxiedService() type for IMAP
+ */
+define("PHPCAS_PROXIED_SERVICE_IMAP", 'CAS_ProxiedService_Imap');
+
+
+/** @} */
+// ------------------------------------------------------------------------
+//  LANGUAGES
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicLang
+ * @{
+ */
+
+define("PHPCAS_LANG_ENGLISH", 'CAS_Languages_English');
+define("PHPCAS_LANG_FRENCH", 'CAS_Languages_French');
+define("PHPCAS_LANG_GREEK", 'CAS_Languages_Greek');
+define("PHPCAS_LANG_GERMAN", 'CAS_Languages_German');
+define("PHPCAS_LANG_JAPANESE", 'CAS_Languages_Japanese');
+define("PHPCAS_LANG_SPANISH", 'CAS_Languages_Spanish');
+define("PHPCAS_LANG_CATALAN", 'CAS_Languages_Catalan');
+
+/** @} */
+
+/**
+ * @addtogroup internalLang
+ * @{
+ */
+
+/**
+ * phpCAS default language (when phpCAS::setLang() is not used)
+ */
+define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH);
+
+/** @} */
+// ------------------------------------------------------------------------
+//  DEBUG
+// ------------------------------------------------------------------------
+/**
+ * @addtogroup publicDebug
+ * @{
+ */
+
+/**
+ * The default directory for the debug file under Unix.
+ */
+define('DEFAULT_DEBUG_DIR', '/tmp/');
+
+/** @} */
+
+// include the class autoloader
+require_once dirname(__FILE__) . '/CAS/Autoload.php';
+
+/**
+ * The phpCAS class is a simple container for the phpCAS library. It provides CAS
+ * authentication for web applications written in PHP.
+ *
+ * @ingroup public
+ * @class phpCAS
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class phpCAS
+{
+
+    /**
+     * This variable is used by the interface class phpCAS.
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_CLIENT;
+
+    /**
+     * This variable is used to store where the initializer is called from
+     * (to print a comprehensive error in case of multiple calls).
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_INIT_CALL;
+
+    /**
+     * This variable is used to store phpCAS debug mode.
+     *
+     * @hideinitializer
+     */
+    private static $_PHPCAS_DEBUG;
+
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * @addtogroup publicInit
+     * @{
+     */
+
+    /**
+     * phpCAS client initializer.
+     *
+     * @param string $server_version  the version of the CAS server
+     * @param string $server_hostname the hostname of the CAS server
+     * @param string $server_port     the port the CAS server is running on
+     * @param string $server_uri      the URI the CAS server is responding on
+     * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
+     * Sign Out/handleLogoutRequests is based on that change)
+     *
+     * @return a newly created CAS_Client object
+     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+     * called, only once, and before all other methods (except phpCAS::getVersion()
+     * and phpCAS::setDebug()).
+     */
+    public static function client($server_version, $server_hostname,
+        $server_port, $server_uri, $changeSessionID = true
+    ) {
+        phpCAS :: traceBegin();
+        if (is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
+        }
+        if (gettype($server_version) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
+        }
+        if (gettype($server_hostname) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
+        }
+        if (gettype($server_port) != 'integer') {
+            phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
+        }
+        if (gettype($server_uri) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
+        }
+
+        // store where the initializer is called from
+        $dbg = debug_backtrace();
+        self::$_PHPCAS_INIT_CALL = array (
+            'done' => true,
+            'file' => $dbg[0]['file'],
+            'line' => $dbg[0]['line'],
+            'method' => __CLASS__ . '::' . __FUNCTION__
+        );
+
+        // initialize the object $_PHPCAS_CLIENT
+        self::$_PHPCAS_CLIENT = new CAS_Client(
+            $server_version, false, $server_hostname, $server_port, $server_uri,
+            $changeSessionID
+        );
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * phpCAS proxy initializer.
+     *
+     * @param string $server_version  the version of the CAS server
+     * @param string $server_hostname the hostname of the CAS server
+     * @param string $server_port     the port the CAS server is running on
+     * @param string $server_uri      the URI the CAS server is responding on
+     * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single
+     * Sign Out/handleLogoutRequests is based on that change)
+     *
+     * @return a newly created CAS_Client object
+     * @note Only one of the phpCAS::client() and phpCAS::proxy functions should be
+     * called, only once, and before all other methods (except phpCAS::getVersion()
+     * and phpCAS::setDebug()).
+     */
+    public static function proxy($server_version, $server_hostname,
+        $server_port, $server_uri, $changeSessionID = true
+    ) {
+        phpCAS :: traceBegin();
+        if (is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
+        }
+        if (gettype($server_version) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
+        }
+        if (gettype($server_hostname) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
+        }
+        if (gettype($server_port) != 'integer') {
+            phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
+        }
+        if (gettype($server_uri) != 'string') {
+            phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
+        }
+
+        // store where the initialzer is called from
+        $dbg = debug_backtrace();
+        self::$_PHPCAS_INIT_CALL = array (
+            'done' => true,
+            'file' => $dbg[0]['file'],
+            'line' => $dbg[0]['line'],
+            'method' => __CLASS__ . '::' . __FUNCTION__
+        );
+
+        // initialize the object $_PHPCAS_CLIENT
+        self::$_PHPCAS_CLIENT = new CAS_Client(
+            $server_version, true, $server_hostname, $server_port, $server_uri,
+            $changeSessionID
+        );
+        phpCAS :: traceEnd();
+    }
+
+    /** @} */
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * @addtogroup publicDebug
+     * @{
+     */
+
+    /**
+     * Set/unset debug mode
+     *
+     * @param string $filename the name of the file used for logging, or false
+     * to stop debugging.
+     *
+     * @return void
+     */
+    public static function setDebug($filename = '')
+    {
+        if ($filename != false && gettype($filename) != 'string') {
+            phpCAS :: error('type mismatched for parameter $dbg (should be false or the name of the log file)');
+        }
+        if ($filename === false) {
+            self::$_PHPCAS_DEBUG['filename'] = false;
+
+        } else {
+            if (empty ($filename)) {
+                if (preg_match('/^Win.*/', getenv('OS'))) {
+                    if (isset ($_ENV['TMP'])) {
+                        $debugDir = $_ENV['TMP'] . '/';
+                    } else {
+                        $debugDir = '';
+                    }
+                } else {
+                    $debugDir = DEFAULT_DEBUG_DIR;
+                }
+                $filename = $debugDir . 'phpCAS.log';
+            }
+
+            if (empty (self::$_PHPCAS_DEBUG['unique_id'])) {
+                self::$_PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))), 0, 4);
+            }
+
+            self::$_PHPCAS_DEBUG['filename'] = $filename;
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+
+            phpCAS :: trace('START phpCAS-' . PHPCAS_VERSION . ' ******************');
+        }
+    }
+
+
+    /**
+     * Logs a string in debug mode.
+     *
+     * @param string $str the string to write
+     *
+     * @return void
+     * @private
+     */
+    public static function log($str)
+    {
+        $indent_str = ".";
+
+
+        if (!empty(self::$_PHPCAS_DEBUG['filename'])) {
+            // Check if file exists and modifiy file permissions to be only
+            // readable by the webserver
+            if (!file_exists(self::$_PHPCAS_DEBUG['filename'])) {
+                touch(self::$_PHPCAS_DEBUG['filename']);
+                // Chmod will fail on windows
+                @chmod(self::$_PHPCAS_DEBUG['filename'], 0600);
+            }
+            for ($i = 0; $i < self::$_PHPCAS_DEBUG['indent']; $i++) {
+
+                $indent_str .= '|    ';
+            }
+            // allow for multiline output with proper identing. Usefull for
+            // dumping cas answers etc.
+            $str2 = str_replace("\n", "\n" . self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str, $str);
+            error_log(self::$_PHPCAS_DEBUG['unique_id'] . ' ' . $indent_str . $str2 . "\n", 3, self::$_PHPCAS_DEBUG['filename']);
+        }
+
+    }
+
+    /**
+     * This method is used by interface methods to print an error and where the
+     * function was originally called from.
+     *
+     * @param string $msg the message to print
+     *
+     * @return void
+     * @private
+     */
+    public static function error($msg)
+    {
+        $dbg = debug_backtrace();
+        $function = '?';
+        $file = '?';
+        $line = '?';
+        if (is_array($dbg)) {
+            for ($i = 1; $i < sizeof($dbg); $i++) {
+                if (is_array($dbg[$i]) && isset($dbg[$i]['class']) ) {
+                    if ($dbg[$i]['class'] == __CLASS__) {
+                        $function = $dbg[$i]['function'];
+                        $file = $dbg[$i]['file'];
+                        $line = $dbg[$i]['line'];
+                    }
+                }
+            }
+        }
+        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";
+        phpCAS :: trace($msg);
+        phpCAS :: traceEnd();
+
+        throw new CAS_GracefullTerminationException(__CLASS__ . "::" . $function . '(): ' . $msg);
+    }
+
+    /**
+     * This method is used to log something in debug mode.
+     *
+     * @param string $str string to log
+     *
+     * @return void
+     */
+    public static function trace($str)
+    {
+        $dbg = debug_backtrace();
+        phpCAS :: log($str . ' [' . basename($dbg[0]['file']) . ':' . $dbg[0]['line'] . ']');
+    }
+
+    /**
+     * This method is used to indicate the start of the execution of a function in debug mode.
+     *
+     * @return void
+     */
+    public static function traceBegin()
+    {
+        $dbg = debug_backtrace();
+        $str = '=> ';
+        if (!empty ($dbg[1]['class'])) {
+            $str .= $dbg[1]['class'] . '::';
+        }
+        $str .= $dbg[1]['function'] . '(';
+        if (is_array($dbg[1]['args'])) {
+            foreach ($dbg[1]['args'] as $index => $arg) {
+                if ($index != 0) {
+                    $str .= ', ';
+                }
+                if (is_object($arg)) {
+                    $str .= get_class($arg);
+                } else {
+                    $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true));
+                }
+            }
+        }
+        if (isset($dbg[1]['file'])) {
+            $file = basename($dbg[1]['file']);
+        } else {
+            $file = 'unknown_file';
+        }
+        if (isset($dbg[1]['line'])) {
+            $line = $dbg[1]['line'];
+        } else {
+            $line = 'unknown_line';
+        }
+        $str .= ') [' . $file . ':' . $line . ']';
+        phpCAS :: log($str);
+        if (!isset(self::$_PHPCAS_DEBUG['indent'])) {
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+        } else {
+            self::$_PHPCAS_DEBUG['indent']++;
+        }
+    }
+
+    /**
+     * This method is used to indicate the end of the execution of a function in
+     * debug mode.
+     *
+     * @param string $res the result of the function
+     *
+     * @return void
+     */
+    public static function traceEnd($res = '')
+    {
+        if (empty(self::$_PHPCAS_DEBUG['indent'])) {
+            self::$_PHPCAS_DEBUG['indent'] = 0;
+        } else {
+            self::$_PHPCAS_DEBUG['indent']--;
+        }
+        $dbg = debug_backtrace();
+        $str = '';
+        if (is_object($res)) {
+            $str .= '<= ' . get_class($res);
+        } else {
+            $str .= '<= ' . str_replace(array("\r\n", "\n", "\r"), "", var_export($res, true));
+        }
+
+        phpCAS :: log($str);
+    }
+
+    /**
+     * This method is used to indicate the end of the execution of the program
+     *
+     * @return void
+     */
+    public static function traceExit()
+    {
+        phpCAS :: log('exit()');
+        while (self::$_PHPCAS_DEBUG['indent'] > 0) {
+            phpCAS :: log('-');
+            self::$_PHPCAS_DEBUG['indent']--;
+        }
+    }
+
+    /** @} */
+    // ########################################################################
+    //  INTERNATIONALIZATION
+    // ########################################################################
+    /**
+    * @addtogroup publicLang
+    * @{
+    */
+
+    /**
+     * This method is used to set the language used by phpCAS.
+     *
+     * @param string $lang string representing the language.
+     *
+     * @return void
+     *
+     * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH
+     * @note Can be called only once.
+     */
+    public static function setLang($lang)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($lang) != 'string') {
+            phpCAS :: error('type mismatched for parameter $lang (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setLang($lang);
+    }
+
+    /** @} */
+    // ########################################################################
+    //  VERSION
+    // ########################################################################
+    /**
+    * @addtogroup public
+    * @{
+    */
+
+    /**
+     * This method returns the phpCAS version.
+     *
+     * @return the phpCAS version.
+     */
+    public static function getVersion()
+    {
+        return PHPCAS_VERSION;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  HTML OUTPUT
+    // ########################################################################
+    /**
+    * @addtogroup publicOutput
+    * @{
+    */
+
+    /**
+     * This method sets the HTML header used for all outputs.
+     *
+     * @param string $header the HTML header.
+     *
+     * @return void
+     */
+    public static function setHTMLHeader($header)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($header) != 'string') {
+            phpCAS :: error('type mismatched for parameter $header (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setHTMLHeader($header);
+    }
+
+    /**
+     * This method sets the HTML footer used for all outputs.
+     *
+     * @param string $footer the HTML footer.
+     *
+     * @return void
+     */
+    public static function setHTMLFooter($footer)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($footer) != 'string') {
+            phpCAS :: error('type mismatched for parameter $footer (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
+    }
+
+    /** @} */
+    // ########################################################################
+    //  PGT STORAGE
+    // ########################################################################
+    /**
+    * @addtogroup publicPGTStorage
+    * @{
+    */
+
+    /**
+     * This method can be used to set a custom PGT storage object.
+     *
+     * @param CAS_PGTStorage $storage a PGT storage object that inherits from the
+     * CAS_PGTStorage class
+     *
+     * @return void
+     */
+    public static function setPGTStorage($storage)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
+        }
+        if ( !($storage instanceof CAS_PGTStorage) ) {
+            phpCAS :: error('type mismatched for parameter $storage (should be a CAS_PGTStorage `object\')');
+        }
+        self::$_PHPCAS_CLIENT->setPGTStorage($storage);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests in a database.
+     *
+     * @param string $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string $username       the username to use when connecting to the
+     * database
+     * @param string $password       the password to use when connecting to the
+     * database
+     * @param string $table          the table to use for storing and retrieving
+     * PGT's
+     * @param string $driver_options any driver options to use when connecting
+     * to the database
+     *
+     * @return void
+     */
+    public static function setPGTStorageDb($dsn_or_pdo, $username='',
+        $password='', $table='', $driver_options=null
+    ) {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
+        }
+        if (gettype($username) != 'string') {
+            phpCAS :: error('type mismatched for parameter $username (should be `string\')');
+        }
+        if (gettype($password) != 'string') {
+            phpCAS :: error('type mismatched for parameter $password (should be `string\')');
+        }
+        if (gettype($table) != 'string') {
+            phpCAS :: error('type mismatched for parameter $table (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests onto the filesystem.
+     *
+     * @param string $path the path where the PGT's should be stored
+     *
+     * @return void
+     */
+    public static function setPGTStorageFile($path = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
+        }
+        if (gettype($path) != 'string') {
+            phpCAS :: error('type mismatched for parameter $path (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
+        phpCAS :: traceEnd();
+    }
+    /** @} */
+    // ########################################################################
+    // ACCESS TO EXTERNAL SERVICES
+    // ########################################################################
+    /**
+    * @addtogroup publicServices
+    * @{
+    */
+
+    /**
+     * Answer a proxy-authenticated service handler.
+     *
+     * @param string $type The service type. One of
+     * PHPCAS_PROXIED_SERVICE_HTTP_GET; PHPCAS_PROXIED_SERVICE_HTTP_POST;
+     * PHPCAS_PROXIED_SERVICE_IMAP
+     *
+     * @return CAS_ProxiedService
+     * @throws InvalidArgumentException If the service type is unknown.
+     */
+    public static function getProxiedService ($type)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        if (gettype($type) != 'string') {
+            phpCAS :: error('type mismatched for parameter $type (should be `string\')');
+        }
+
+        $res = self::$_PHPCAS_CLIENT->getProxiedService($type);
+
+        phpCAS :: traceEnd();
+        return $res;
+    }
+
+    /**
+     * Initialize a proxied-service handler with the proxy-ticket it should use.
+     *
+     * @param CAS_ProxiedService $proxiedService Proxied Service Handler
+     *
+     * @return void
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *         The code of the Exception will be one of:
+     *                 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_FAILURE
+     */
+    public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+
+        self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
+    }
+
+    /**
+     * This method is used to access an HTTP[S] service.
+     *
+     * @param string $url       the service to access.
+     * @param string &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$output   the output of the service (also used to give an
+     * error message on failure).
+     *
+     * @return bool true on success, false otherwise (in this later case,
+     * $err_code gives the reason why it failed and $output contains an error
+     * message).
+     */
+    public static function serviceWeb($url, & $err_code, & $output)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+
+        $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
+
+        phpCAS :: traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method is used to access an IMAP/POP3/NNTP service.
+     *
+     * @param string $url       a string giving the URL of the service,
+     * including the mailing box for IMAP URLs, as accepted by imap_open().
+     * @param string $service   a string giving for CAS retrieve Proxy ticket
+     * @param string $flags     options given to imap_open().
+     * @param string &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$err_msg  an error message on failure
+     * @param string &$pt       the Proxy Ticket (PT) retrieved from the CAS
+     * server to access the URL on success, false on error).
+     *
+     * @return object IMAP stream on success, false otherwise (in this later
+     * case, $err_code gives the reason why it failed and $err_msg contains an
+     * error message).
+     */
+    public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+
+        if (gettype($flags) != 'integer') {
+            phpCAS :: error('type mismatched for parameter $flags (should be `integer\')');
+        }
+
+        $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
+
+        phpCAS :: traceEnd($res);
+        return $res;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  AUTHENTICATION
+    // ########################################################################
+    /**
+    * @addtogroup publicAuth
+    * @{
+    */
+
+    /**
+     * Set the times authentication will be cached before really accessing the
+     * CAS server in gateway mode:
+     * - -1: check only once, and then never again (until you pree login)
+     * - 0: always check
+     * - n: check every "n" time
+     *
+     * @param int $n an integer.
+     *
+     * @return void
+     */
+    public static function setCacheTimesForAuthRecheck($n)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($n) != 'integer') {
+            phpCAS :: error('type mismatched for parameter $n (should be `integer\')');
+        }
+        self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
+    }
+
+    /**
+     * Set a callback function to be run when a user authenticates.
+     *
+     * The callback function will be passed a $logoutTicket as its first
+     * parameter, followed by any $additionalArgs you pass. The $logoutTicket
+     * parameter is an opaque string that can be used to map the session-id to
+     * logout request in order to support single-signout in applications that
+     * manage their own sessions (rather than letting phpCAS start the session).
+     *
+     * phpCAS::forceAuthentication() will always exit and forward client unless
+     * they are already authenticated. To perform an action at the moment the user
+     * logs in (such as registering an account, performing logging, etc), register
+     * a callback function here.
+     *
+     * @param string $function       Callback function
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+
+        self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
+    }
+
+    /**
+     * Set a callback function to be run when a single-signout request is
+     * received. The callback function will be passed a $logoutTicket as its
+     * first parameter, followed by any $additionalArgs you pass. The
+     * $logoutTicket parameter is an opaque string that can be used to map a
+     * session-id to the logout request in order to support single-signout in
+     * applications that manage their own sessions (rather than letting phpCAS
+     * start and destroy the session).
+     *
+     * @param string $function       Callback function
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+
+        self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
+    }
+
+    /**
+     * This method is called to check if the user is already authenticated
+     * locally or has a global cas session. A already existing cas session is
+     * determined by a cas gateway call.(cas login call without any interactive
+     * prompt)
+     *
+     * @return true when the user is authenticated, false when a previous
+     * gateway login failed or the function will not return if the user is
+     * redirected to the cas server for a gateway login attempt
+     */
+    public static function checkAuthentication()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+
+        $auth = self::$_PHPCAS_CLIENT->checkAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        phpCAS :: traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * This method is called to force authentication if the user was not already
+     * authenticated. If the user is not authenticated, halt by redirecting to
+     * the CAS server.
+     *
+     * @return bool Authentication
+     */
+    public static function forceAuthentication()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+
+        $auth = self::$_PHPCAS_CLIENT->forceAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        /*             if (!$auth) {
+         phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
+        self::$_PHPCAS_CLIENT->forceAuthentication();
+        } else {
+        phpCAS :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)');
+        }*/
+
+        phpCAS :: traceEnd();
+        return $auth;
+    }
+
+    /**
+     * This method is called to renew the authentication.
+     *
+     * @return void
+     **/
+    public static function renewAuthentication()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        $auth = self::$_PHPCAS_CLIENT->renewAuthentication();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        //self::$_PHPCAS_CLIENT->renewAuthentication();
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is called to check if the user is authenticated (previously or by
+     * tickets given in the URL).
+     *
+     * @return true when the user is authenticated.
+     */
+    public static function isAuthenticated()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+
+        // call the isAuthenticated method of the $_PHPCAS_CLIENT object
+        $auth = self::$_PHPCAS_CLIENT->isAuthenticated();
+
+        // store where the authentication has been checked and the result
+        self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
+
+        phpCAS :: traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * Checks whether authenticated based on $_SESSION. Useful to avoid
+     * server calls.
+     *
+     * @return bool true if authenticated, false otherwise.
+     * @since 0.4.22 by Brendan Arnold
+     */
+    public static function isSessionAuthenticated()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
+    }
+
+    /**
+     * This method returns the CAS user's login name.
+     *
+     * @return string the login name of the authenticated user
+     * @warning should not be called only after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     * */
+    public static function getUser()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        return self::$_PHPCAS_CLIENT->getUser();
+    }
+
+    /**
+     * Answer attributes about the authenticated user.
+     *
+     * @warning should not be called only after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     *
+     * @return array
+     */
+    public static function getAttributes()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        return self::$_PHPCAS_CLIENT->getAttributes();
+    }
+
+    /**
+     * Answer true if there are attributes for the authenticated user.
+     *
+     * @warning should not be called only after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     *
+     * @return bool
+     */
+    public static function hasAttributes()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        return self::$_PHPCAS_CLIENT->hasAttributes();
+    }
+
+    /**
+     * Answer true if an attribute exists for the authenticated user.
+     *
+     * @param string $key attribute name
+     *
+     * @return bool
+     * @warning should not be called only after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     */
+    public static function hasAttribute($key)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        return self::$_PHPCAS_CLIENT->hasAttribute($key);
+    }
+
+    /**
+     * Answer an attribute for the authenticated user.
+     *
+     * @param string $key attribute name
+     *
+     * @return mixed string for a single value or an array if multiple values exist.
+     * @warning should not be called only after phpCAS::forceAuthentication()
+     * or phpCAS::checkAuthentication().
+     */
+    public static function getAttribute($key)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
+        }
+        if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
+            phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
+        }
+        return self::$_PHPCAS_CLIENT->getAttribute($key);
+    }
+
+    /**
+     * Handle logout requests.
+     *
+     * @param bool  $check_client    additional safety check
+     * @param array $allowed_clients array of allowed clients
+     *
+     * @return void
+     */
+    public static function handleLogoutRequests($check_client = true, $allowed_clients = false)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
+    }
+
+    /**
+     * This method returns the URL to be used to login.
+     * or phpCAS::isAuthenticated().
+     *
+     * @return the login name of the authenticated user
+     */
+    public static function getServerLoginURL()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        return self::$_PHPCAS_CLIENT->getServerLoginURL();
+    }
+
+    /**
+     * Set the login URL of the CAS server.
+     *
+     * @param string $url the login URL
+     *
+     * @return void
+     * @since 0.4.21 by Wyman Chan
+     */
+    public static function setServerLoginURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string`)');
+        }
+        self::$_PHPCAS_CLIENT->setServerLoginURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the serviceValidate URL of the CAS server.
+     * Used only in CAS 1.0 validations
+     *
+     * @param string $url the serviceValidate URL
+     *
+     * @return void
+     */
+    public static function setServerServiceValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string`)');
+        }
+        self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the proxyValidate URL of the CAS server.
+     * Used for all CAS 2.0 validations
+     *
+     * @param string $url the proxyValidate URL
+     *
+     * @return void
+     */
+    public static function setServerProxyValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string`)');
+        }
+        self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the samlValidate URL of the CAS server.
+     *
+     * @param string $url the samlValidate URL
+     *
+     * @return void
+     */
+    public static function setServerSamlValidateURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be`string\')');
+        }
+        self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method returns the URL to be used to login.
+     * or phpCAS::isAuthenticated().
+     *
+     * @return the login name of the authenticated user
+     */
+    public static function getServerLogoutURL()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
+        }
+        return self::$_PHPCAS_CLIENT->getServerLogoutURL();
+    }
+
+    /**
+     * Set the logout URL of the CAS server.
+     *
+     * @param string $url the logout URL
+     *
+     * @return void
+     * @since 0.4.21 by Wyman Chan
+     */
+    public static function setServerLogoutURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error(
+                'this method should only be called after' . __CLASS__ . '::client()'
+            );
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error(
+                'type mismatched for parameter $url (should be `string`)'
+            );
+        }
+        self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS.
+     *
+     * @param string $params an array that contains the optional url and
+     * service parameters that will be passed to the CAS server
+     *
+     * @return void
+     */
+    public static function logout($params = "")
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        $parsedParams = array ();
+        if ($params != "") {
+            if (is_string($params)) {
+                phpCAS :: error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead');
+            }
+            if (!is_array($params)) {
+                phpCAS :: error('type mismatched for parameter $params (should be `array\')');
+            }
+            foreach ($params as $key => $value) {
+                if ($key != "service" && $key != "url") {
+                    phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\'');
+                }
+                $parsedParams[$key] = $value;
+            }
+        }
+        self::$_PHPCAS_CLIENT->logout($parsedParams);
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param service $service a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     */
+    public static function logoutWithRedirectService($service)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (!is_string($service)) {
+            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(array ( "service" => $service ));
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param string $url a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     * @deprecated The url parameter has been removed from the CAS server as of
+     * version 3.3.5.1
+     */
+    public static function logoutWithUrl($url)
+    {
+        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (!is_string($url)) {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(array ( "url" => $url ));
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * This method is used to logout from CAS. Halts by redirecting to the CAS
+     * server.
+     *
+     * @param string $service a URL that will be transmitted to the CAS server
+     * @param string $url     a URL that will be transmitted to the CAS server
+     *
+     * @return void
+     *
+     * @deprecated The url parameter has been removed from the CAS server as of
+     * version 3.3.5.1
+     */
+    public static function logoutWithRedirectServiceAndUrl($service, $url)
+    {
+        trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (!is_string($service)) {
+            phpCAS :: error('type mismatched for parameter $service (should be `string\')');
+        }
+        if (!is_string($url)) {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->logout(
+            array (
+                "service" => $service,
+                "url" => $url
+            )
+        );
+        // never reached
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the fixed URL that will be used by the CAS server to transmit the
+     * PGT. When this method is not called, a phpCAS script uses its own URL
+     * for the callback.
+     *
+     * @param string $url the URL
+     *
+     * @return void
+     */
+    public static function setFixedCallbackURL($url = '')
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (!self::$_PHPCAS_CLIENT->isProxy()) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setCallbackURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set the fixed URL that will be set as the CAS service parameter. When this
+     * method is not called, a phpCAS script uses its own URL.
+     *
+     * @param string $url the URL
+     *
+     * @return void
+     */
+    public static function setFixedServiceURL($url)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($url) != 'string') {
+            phpCAS :: error('type mismatched for parameter $url (should be `string\')');
+        }
+        self::$_PHPCAS_CLIENT->setURL($url);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Get the URL that is set as the CAS service parameter.
+     *
+     * @return string Service Url
+     */
+    public static function getServiceURL()
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        return (self::$_PHPCAS_CLIENT->getURL());
+    }
+
+    /**
+     * Retrieve a Proxy Ticket from the CAS server.
+     *
+     * @param string $target_service Url string of service to proxy
+     * @param string &$err_code      error code
+     * @param string &$err_msg       error message
+     *
+     * @return string Proxy Ticket
+     */
+    public static function retrievePT($target_service, & $err_code, & $err_msg)
+    {
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($target_service) != 'string') {
+            phpCAS :: error('type mismatched for parameter $target_service(should be `string\')');
+        }
+        return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
+    }
+
+    /**
+     * Set the certificate of the CAS server CA and if the CN should be properly
+     * verified.
+     *
+     * @param string $cert        CA certificate file name
+     * @param bool   $validate_cn Validate CN in certificate (default true)
+     *
+     * @return void
+     */
+    public static function setCasServerCACert($cert, $validate_cn = true)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (gettype($cert) != 'string') {
+            phpCAS :: error('type mismatched for parameter $cert (should be `string\')');
+        }
+        if (gettype($validate_cn) != 'boolean') {\r
+            phpCAS :: error('type mismatched for parameter $validate_cn (should be `boolean\')');\r
+        }
+        self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Set no SSL validation for the CAS server.
+     *
+     * @return void
+     */
+    public static function setNoCasServerValidation()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
+        self::$_PHPCAS_CLIENT->setNoCasServerValidation();
+        phpCAS :: traceEnd();
+    }
+
+
+    /**
+     * Disable the removal of a CAS-Ticket from the URL when authenticating
+     * DISABLING POSES A SECURITY RISK:
+     * We normally remove the ticket by an additional redirect as a security
+     * precaution to prevent a ticket in the HTTP_REFERRER or be carried over in
+     * the URL parameter
+     *
+     * @return void
+     */
+    public static function setNoClearTicketsFromUrl()
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
+        phpCAS :: traceEnd();
+    }
+
+    /** @} */
+
+    /**
+     * Change CURL options.
+     * CURL is used to connect through HTTPS to CAS server
+     *
+     * @param string $key   the option key
+     * @param string $value the value to set
+     *
+     * @return void
+     */
+    public static function setExtraCurlOption($key, $value)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * If you want your service to be proxied you have to enable it (default
+     * disabled) and define an accepable list of proxies that are allowed to
+     * proxy your service.
+     *
+     * Add each allowed proxy definition object. For the normal CAS_ProxyChain
+     * class, the constructor takes an array of proxies to match. The list is in
+     * reverse just as seen from the service. Proxies have to be defined in reverse
+     * from the service to the user. If a user hits service A and gets proxied via
+     * B to service C the list of acceptable on C would be array(B,A). The definition
+     * of an individual proxy can be either a string or a regexp (preg_match is used)
+     * that will be matched against the proxy list supplied by the cas server
+     * when validating the proxy tickets. The strings are compared starting from
+     * the beginning and must fully match with the proxies in the list.
+     * Example:
+     *                 phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+     *                         'https://app.example.com/'
+     *                 )));
+     *                 phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+     *                         '/^https:\/\/app[0-9]\.example\.com\/rest\//',
+     *                         'http://client.example.com/'
+     *                 )));
+     *
+     * For quick testing or in certain production screnarios you might want to
+     * allow allow any other valid service to proxy your service. To do so, add
+     * the "Any" chain:
+     *         phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+     * THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+     * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+     * ON THIS SERVICE.
+     *
+     * @param CAS_ProxyChain_Interface $proxy_chain A proxy-chain that will be
+     * matched against the proxies requesting access
+     *
+     * @return void
+     */
+    public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0) {
+            phpCAS :: error('this method can only be used with the cas 2.0 protool');
+        }
+        self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
+        phpCAS :: traceEnd();
+    }
+
+    /**
+     * Answer an array of proxies that are sitting in front of this application.
+     * This method will only return a non-empty array if we have received and
+     * validated a Proxy Ticket.
+     *
+     * @return array
+     * @access public
+     * @since 6/25/09
+     */
+    public static function getProxies ()
+    {
+        if ( !is_object(self::$_PHPCAS_CLIENT) ) {
+            phpCAS::error('this method should only be called after '.__CLASS__.'::client()');
+        }
+
+        return(self::$_PHPCAS_CLIENT->getProxies());
+    }
+
+    // ########################################################################
+    // PGTIOU/PGTID and logoutRequest rebroadcasting
+    // ########################################################################
+
+    /**
+     * Add a pgtIou/pgtId and logoutRequest rebroadcast node.
+     *
+     * @param string $rebroadcastNodeUrl The rebroadcast node URL. Can be
+     * hostname or IP.
+     *
+     * @return void
+     */
+    public static function addRebroadcastNode($rebroadcastNodeUrl)
+    {
+        phpCAS::traceBegin();
+        phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) {
+            phpCAS::error('type mismatched for parameter $rebroadcastNodeUrl (should be `url\')');
+        }
+        self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method is used to add header parameters when rebroadcasting
+     * pgtIou/pgtId or logoutRequest.
+     *
+     * @param String $header Header to send when rebroadcasting.
+     *
+     * @return void
+     */
+    public static function addRebroadcastHeader($header)
+    {
+        phpCAS :: traceBegin();
+        if (!is_object(self::$_PHPCAS_CLIENT)) {
+            phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
+        }
+        self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
+        phpCAS :: traceEnd();
+    }
+}
+
+// ########################################################################
+// DOCUMENTATION
+// ########################################################################
+
+// ########################################################################
+//  MAIN PAGE
+
+/**
+ * @mainpage
+ *
+ * The following pages only show the source documentation.
+ *
+ */
+
+// ########################################################################
+//  MODULES DEFINITION
+
+/** @defgroup public User interface */
+
+/** @defgroup publicInit Initialization
+ *  @ingroup public */
+
+/** @defgroup publicAuth Authentication
+ *  @ingroup public */
+
+/** @defgroup publicServices Access to external services
+ *  @ingroup public */
+
+/** @defgroup publicConfig Configuration
+ *  @ingroup public */
+
+/** @defgroup publicLang Internationalization
+ *  @ingroup publicConfig */
+
+/** @defgroup publicOutput HTML output
+ *  @ingroup publicConfig */
+
+/** @defgroup publicPGTStorage PGT storage
+ *  @ingroup publicConfig */
+
+/** @defgroup publicDebug Debugging
+ *  @ingroup public */
+
+/** @defgroup internal Implementation */
+
+/** @defgroup internalAuthentication Authentication
+ *  @ingroup internal */
+
+/** @defgroup internalBasic CAS Basic client features (CAS 1.0, Service Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalProxy CAS Proxy features (CAS 2.0, Proxy Granting Tickets)
+ *  @ingroup internal */
+
+/** @defgroup internalSAML CAS SAML features (SAML 1.1)
+ *  @ingroup internal */
+
+/** @defgroup internalPGTStorage PGT storage
+ *  @ingroup internalProxy */
+
+/** @defgroup internalPGTStorageDb PGT storage in a database
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalPGTStorageFile PGT storage on the filesystem
+ *  @ingroup internalPGTStorage */
+
+/** @defgroup internalCallback Callback from the CAS server
+ *  @ingroup internalProxy */
+
+/** @defgroup internalProxyServices Proxy other services
+ *  @ingroup internalProxy */
+
+/** @defgroup internalService CAS client features (CAS 2.0, Proxied service)
+ *  @ingroup internal */
+
+/** @defgroup internalConfig Configuration
+ *  @ingroup internal */
+
+/** @defgroup internalBehave Internal behaviour of phpCAS
+ *  @ingroup internalConfig */
+
+/** @defgroup internalOutput HTML output
+ *  @ingroup internalConfig */
+
+/** @defgroup internalLang Internationalization
+ *  @ingroup internalConfig
+ *
+ * To add a new language:
+ * - 1. define a new constant PHPCAS_LANG_XXXXXX in CAS/CAS.php
+ * - 2. copy any file from CAS/languages to CAS/languages/XXXXXX.php
+ * - 3. Make the translations
+ */
+
+/** @defgroup internalDebug Debugging
+ *  @ingroup internal */
+
+/** @defgroup internalMisc Miscellaneous
+ *  @ingroup internal */
+
+// ########################################################################
+//  EXAMPLES
+
+/**
+ * @example example_simple.php
+ */
+/**
+ * @example example_service.php
+ */
+/**
+ * @example example_service_that_proxies.php
+ */
+/**
+ * @example example_service_POST.php
+ */
+/**
+ * @example example_proxy_serviceWeb.php
+ */
+/**
+ * @example example_proxy_serviceWeb_chaining.php
+ */
+/**
+ * @example example_proxy_POST.php
+ */
+/**
+ * @example example_proxy_GET.php
+ */
+/**
+ * @example example_lang.php
+ */
+/**
+ * @example example_html.php
+ */
+/**
+ * @example example_pgt_storage_file.php
+ */
+/**
+ * @example example_pgt_storage_db.php
+ */
+/**
+ * @example example_gateway.php
+ */
+/**
+ * @example example_logout.php
+ */
+/**
+ * @example example_rebroadcast.php
+ */
+/**
+ * @example example_custom_urls.php
+ */
+/**
+ * @example example_advanced_saml11.php
+ */
+?>
diff --git a/CAS/CAS/AuthenticationException.php b/CAS/CAS/AuthenticationException.php
new file mode 100644 (file)
index 0000000..801156e
--- /dev/null
@@ -0,0 +1,107 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/AuthenticationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to interact with phpCAS.
+ *
+ * Proxy service handlers must implement this interface as well as call
+ * phpCAS::initializeProxiedService($this) at some point in their implementation.
+ *
+ * While not required, proxy-authenticated service handlers are encouraged to
+ * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.
+ *
+ * @class    CAS_AuthenticationException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_AuthenticationException
+extends RuntimeException
+implements CAS_Exception
+{
+
+    /**
+     * This method is used to print the HTML output when the user was not
+     * authenticated.
+     *
+     * @param CAS_Client $client       phpcas client
+     * @param string     $failure      the failure that occured
+     * @param string     $cas_url      the URL the CAS server was asked for
+     * @param bool       $no_response  the response from the CAS server (other
+     * parameters are ignored if TRUE)
+     * @param bool       $bad_response bad response from the CAS server ($err_code
+     * and $err_msg ignored if TRUE)
+     * @param string     $cas_response the response of the CAS server
+     * @param int        $err_code     the error code given by the CAS server
+     * @param string     $err_msg      the error message given by the CAS server
+     */
+    public function __construct($client,$failure,$cas_url,$no_response,
+        $bad_response='',$cas_response='',$err_code='',$err_msg=''
+    ) {
+        phpCAS::traceBegin();
+        $lang = $client->getLangObj();
+        $client->printHTMLHeader($lang->getAuthenticationFailed());
+        printf(
+            $lang->getYouWereNotAuthenticated(),
+            htmlentities($client->getURL()),
+            $_SERVER['SERVER_ADMIN']
+        );
+        phpCAS::trace('CAS URL: '.$cas_url);
+        phpCAS::trace('Authentication failure: '.$failure);
+        if ( $no_response ) {
+            phpCAS::trace('Reason: no response from the CAS server');
+        } else {
+            if ( $bad_response ) {
+                phpCAS::trace('Reason: bad response from the CAS server');
+            } else {
+                switch ($client->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    phpCAS::trace('Reason: CAS error');
+                    break;
+                case CAS_VERSION_2_0:
+                    if ( empty($err_code) ) {
+                        phpCAS::trace('Reason: no CAS error');
+                    } else {
+                        phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
+                    }
+                    break;
+                }
+            }
+            phpCAS::trace('CAS response: '.$cas_response);
+        }
+        $client->printHTMLFooter();
+        phpCAS::traceExit();
+    }
+
+}
+?>
diff --git a/CAS/CAS/Autoload.php b/CAS/CAS/Autoload.php
new file mode 100644 (file)
index 0000000..c7d436e
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Autoloader Class
+ *
+ *  PHP Version 5
+ *
+ * @file      CAS/Autoload.php
+ * @category  Authentication
+ * @package   SimpleCAS
+ * @author    Brett Bieber <brett.bieber@gmail.com>
+ * @copyright 2008 Regents of the University of Nebraska
+ * @license   http://www1.unl.edu/wdn/wiki/Software_License BSD License
+ * @link      http://code.google.com/p/simplecas/
+ **/
+
+/**
+ * Autoload a class
+ *
+ * @param string $class Classname to load
+ *
+ * @return bool
+ */
+function CAS_autoload($class)
+{
+    // Static to hold the Include Path to CAS
+    static $include_path;
+    // Setup the include path if it's not already set from a previous call
+    if (!$include_path) {
+        $include_path = dirname(dirname(__FILE__));
+    }
+    if (substr($class, 0, 4) !== 'CAS_') {
+        return false;
+    }
+    // Declare local variable to store the expected full path to the file
+    $file_path = $include_path . '/' . str_replace('_', '/', $class) . '.php';
+
+    $fp = @fopen($file_path, 'r', true);
+    if ($fp) {
+        fclose($fp);
+        include $file_path;
+        if (!class_exists($class, false) && !interface_exists($class, false)) {
+            die(
+                new Exception(
+                    'Class ' . $class . ' was not present in ' .
+                    $file_path .
+                    ' [CAS_autoload]'
+                )
+            );
+        }
+        return true;
+    }
+    $e = new Exception(
+        'Class ' . $class . ' could not be loaded from ' .
+        $file_path . ', file does not exist (Path="'
+        . $include_path .'") [CAS_autoload]'
+    );
+    $trace = $e->getTrace();
+    if (isset($trace[2]) && isset($trace[2]['function'])
+        && in_array($trace[2]['function'], array('class_exists', 'interface_exists'))
+    ) {
+        return false;
+    }
+    if (isset($trace[1]) && isset($trace[1]['function'])
+        && in_array($trace[1]['function'], array('class_exists', 'interface_exists'))
+    ) {
+        return false;
+    }
+    die ((string) $e);
+}
+
+// set up __autoload
+if (function_exists('spl_autoload_register')) {
+    if (!(spl_autoload_functions()) || !in_array('CAS_autoload', spl_autoload_functions())) {
+        spl_autoload_register('CAS_autoload');
+        if (function_exists('__autoload') && !in_array('__autoload', spl_autoload_functions())) {
+            // __autoload() was being used, but now would be ignored, add
+            // it to the autoload stack
+            spl_autoload_register('__autoload');
+        }
+    }
+} elseif (!function_exists('__autoload')) {
+
+    /**
+     * Autoload a class
+     *
+     * @param string $class Class name
+     *
+     * @return bool
+     */
+    function __autoload($class)
+    {
+        return CAS_autoload($class);
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Client.php b/CAS/CAS/Client.php
new file mode 100644 (file)
index 0000000..f5d0d4e
--- /dev/null
@@ -0,0 +1,3401 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Client.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * The CAS_Client class is a client interface that provides CAS authentication
+ * to PHP applications.
+ *
+ * @class    CAS_Client
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @author   Olivier Berger <olivier.berger@it-sudparis.eu>
+ * @author   Brett Bieber <brett.bieber@gmail.com>
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+
+class CAS_Client
+{
+
+    // ########################################################################
+    //  HTML OUTPUT
+    // ########################################################################
+    /**
+    * @addtogroup internalOutput
+    * @{
+    */
+
+    /**
+     * This method filters a string by replacing special tokens by appropriate values
+     * and prints it. The corresponding tokens are taken into account:
+     * - __CAS_VERSION__
+     * - __PHPCAS_VERSION__
+     * - __SERVER_BASE_URL__
+     *
+     * Used by CAS_Client::PrintHTMLHeader() and CAS_Client::printHTMLFooter().
+     *
+     * @param string $str the string to filter and output
+     *
+     * @return void
+     */
+    private function _htmlFilterOutput($str)
+    {
+        $str = str_replace('__CAS_VERSION__', $this->getServerVersion(), $str);
+        $str = str_replace('__PHPCAS_VERSION__', phpCAS::getVersion(), $str);
+        $str = str_replace('__SERVER_BASE_URL__', $this->_getServerBaseURL(), $str);
+        echo $str;
+    }
+
+    /**
+     * A string used to print the header of HTML pages. Written by
+     * CAS_Client::setHTMLHeader(), read by CAS_Client::printHTMLHeader().
+     *
+     * @hideinitializer
+     * @see CAS_Client::setHTMLHeader, CAS_Client::printHTMLHeader()
+     */
+    private $_output_header = '';
+
+    /**
+     * This method prints the header of the HTML output (after filtering). If
+     * CAS_Client::setHTMLHeader() was not used, a default header is output.
+     *
+     * @param string $title the title of the page
+     *
+     * @return void
+     * @see _htmlFilterOutput()
+     */
+    public function printHTMLHeader($title)
+    {
+        $this->_htmlFilterOutput(
+            str_replace(
+                '__TITLE__', $title,
+                (empty($this->_output_header)
+                ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
+                : $this->_output_header)
+            )
+        );
+    }
+
+    /**
+     * A string used to print the footer of HTML pages. Written by
+     * CAS_Client::setHTMLFooter(), read by printHTMLFooter().
+     *
+     * @hideinitializer
+     * @see CAS_Client::setHTMLFooter, CAS_Client::printHTMLFooter()
+     */
+    private $_output_footer = '';
+
+    /**
+     * This method prints the footer of the HTML output (after filtering). If
+     * CAS_Client::setHTMLFooter() was not used, a default footer is output.
+     *
+     * @return void
+     * @see _htmlFilterOutput()
+     */
+    public function printHTMLFooter()
+    {
+        $lang = $this->getLangObj();
+        $this->_htmlFilterOutput(
+            empty($this->_output_footer)?
+            ('<hr><address>phpCAS __PHPCAS_VERSION__ '
+            .$lang->getUsingServer()
+            .' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')
+            :$this->_output_footer
+        );
+    }
+
+    /**
+     * This method set the HTML header used for all outputs.
+     *
+     * @param string $header the HTML header.
+     *
+     * @return void
+     */
+    public function setHTMLHeader($header)
+    {
+        $this->_output_header = $header;
+    }
+
+    /**
+     * This method set the HTML footer used for all outputs.
+     *
+     * @param string $footer the HTML footer.
+     *
+     * @return void
+     */
+    public function setHTMLFooter($footer)
+    {
+        $this->_output_footer = $footer;
+    }
+
+
+    /** @} */
+
+
+    // ########################################################################
+    //  INTERNATIONALIZATION
+    // ########################################################################
+    /**
+    * @addtogroup internalLang
+    * @{
+    */
+    /**
+     * A string corresponding to the language used by phpCAS. Written by
+     * CAS_Client::setLang(), read by CAS_Client::getLang().
+
+     * @note debugging information is always in english (debug purposes only).
+     */
+    private $_lang = PHPCAS_LANG_DEFAULT;
+
+    /**
+     * This method is used to set the language used by phpCAS.
+     *
+     * @param string $lang representing the language.
+     *
+     * @return void
+     */
+    public function setLang($lang)
+    {
+        phpCAS::traceBegin();
+        $obj = new $lang();
+        if (!($obj instanceof CAS_Languages_LanguageInterface)) {
+            throw new CAS_InvalidArgumentException('$className must implement the CAS_Languages_LanguageInterface');
+        }
+        $this->_lang = $lang;
+        phpCAS::traceEnd();
+    }
+    /**
+     * Create the language
+     *
+     * @return CAS_Languages_LanguageInterface object implementing the class
+     */
+    public function getLangObj()
+    {
+        $classname = $this->_lang;
+        return new $classname();
+    }
+
+    /** @} */
+    // ########################################################################
+    //  CAS SERVER CONFIG
+    // ########################################################################
+    /**
+    * @addtogroup internalConfig
+    * @{
+    */
+
+    /**
+     * a record to store information about the CAS server.
+     * - $_server['version']: the version of the CAS server
+     * - $_server['hostname']: the hostname of the CAS server
+     * - $_server['port']: the port the CAS server is running on
+     * - $_server['uri']: the base URI the CAS server is responding on
+     * - $_server['base_url']: the base URL of the CAS server
+     * - $_server['login_url']: the login URL of the CAS server
+     * - $_server['service_validate_url']: the service validating URL of the
+     *   CAS server
+     * - $_server['proxy_url']: the proxy URL of the CAS server
+     * - $_server['proxy_validate_url']: the proxy validating URL of the CAS server
+     * - $_server['logout_url']: the logout URL of the CAS server
+     *
+     * $_server['version'], $_server['hostname'], $_server['port'] and
+     * $_server['uri'] are written by CAS_Client::CAS_Client(), read by
+     * CAS_Client::getServerVersion(), CAS_Client::_getServerHostname(),
+     * CAS_Client::_getServerPort() and CAS_Client::_getServerURI().
+     *
+     * The other fields are written and read by CAS_Client::_getServerBaseURL(),
+     * CAS_Client::getServerLoginURL(), CAS_Client::getServerServiceValidateURL(),
+     * CAS_Client::getServerProxyValidateURL() and CAS_Client::getServerLogoutURL().
+     *
+     * @hideinitializer
+     */
+    private $_server = array(
+        'version' => -1,
+        'hostname' => 'none',
+        'port' => -1,
+        'uri' => 'none');
+
+    /**
+     * This method is used to retrieve the version of the CAS server.
+     *
+     * @return string the version of the CAS server.
+     */
+    public function getServerVersion()
+    {
+        return $this->_server['version'];
+    }
+
+    /**
+     * This method is used to retrieve the hostname of the CAS server.
+     *
+     * @return string the hostname of the CAS server.
+     */
+    private function _getServerHostname()
+    {
+        return $this->_server['hostname'];
+    }
+
+    /**
+     * This method is used to retrieve the port of the CAS server.
+     *
+     * @return string the port of the CAS server.
+     */
+    private function _getServerPort()
+    {
+        return $this->_server['port'];
+    }
+
+    /**
+     * This method is used to retrieve the URI of the CAS server.
+     *
+     * @return string a URI.
+     */
+    private function _getServerURI()
+    {
+        return $this->_server['uri'];
+    }
+
+    /**
+     * This method is used to retrieve the base URL of the CAS server.
+     *
+     * @return string a URL.
+     */
+    private function _getServerBaseURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['base_url']) ) {
+            $this->_server['base_url'] = 'https://' . $this->_getServerHostname();
+            if ($this->_getServerPort()!=443) {
+                $this->_server['base_url'] .= ':'
+                .$this->_getServerPort();
+            }
+            $this->_server['base_url'] .= $this->_getServerURI();
+        }
+        return $this->_server['base_url'];
+    }
+
+    /**
+     * This method is used to retrieve the login URL of the CAS server.
+     *
+     * @param bool $gateway true to check authentication, false to force it
+     * @param bool $renew   true to force the authentication with the CAS server
+     *
+     * @return a URL.
+     * @note It is recommended that CAS implementations ignore the "gateway"
+     * parameter if "renew" is set
+     */
+    public function getServerLoginURL($gateway=false,$renew=false)
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['login_url']) ) {
+            $this->_server['login_url'] = $this->_getServerBaseURL();
+            $this->_server['login_url'] .= 'login?service=';
+            $this->_server['login_url'] .= urlencode($this->getURL());
+        }
+        $url = $this->_server['login_url'];
+        if ($renew) {
+            // It is recommended that when the "renew" parameter is set, its
+            // value be "true"
+            $url = $this->_buildQueryUrl($url, 'renew=true');
+        } elseif ($gateway) {
+            // It is recommended that when the "gateway" parameter is set, its
+            // value be "true"
+            $url = $this->_buildQueryUrl($url, 'gateway=true');
+        }
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+    /**
+     * This method sets the login URL of the CAS server.
+     *
+     * @param string $url the login URL
+     *
+     * @return string login url
+     */
+    public function setServerLoginURL($url)
+    {
+        return $this->_server['login_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the serviceValidate URL of the CAS server.
+     *
+     * @param string $url the serviceValidate URL
+     *
+     * @return string serviceValidate URL
+     */
+    public function setServerServiceValidateURL($url)
+    {
+        return $this->_server['service_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the proxyValidate URL of the CAS server.
+     *
+     * @param string $url the proxyValidate URL
+     *
+     * @return string proxyValidate URL
+     */
+    public function setServerProxyValidateURL($url)
+    {
+        return $this->_server['proxy_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method sets the samlValidate URL of the CAS server.
+     *
+     * @param string $url the samlValidate URL
+     *
+     * @return string samlValidate URL
+     */
+    public function setServerSamlValidateURL($url)
+    {
+        return $this->_server['saml_validate_url'] = $url;
+    }
+
+
+    /**
+     * This method is used to retrieve the service validating URL of the CAS server.
+     *
+     * @return string serviceValidate URL.
+     */
+    public function getServerServiceValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['service_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['service_validate_url'] = $this->_getServerBaseURL()
+                .'validate';
+                break;
+            case CAS_VERSION_2_0:
+                $this->_server['service_validate_url'] = $this->_getServerBaseURL()
+                .'serviceValidate';
+                break;
+            }
+        }
+        $url = $this->_buildQueryUrl($this->_server['service_validate_url'], 'service='.urlencode($this->getURL()));
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+    /**
+     * This method is used to retrieve the SAML validating URL of the CAS server.
+     *
+     * @return string samlValidate URL.
+     */
+    public function getServerSamlValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['saml_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case SAML_VERSION_1_1:
+                $this->_server['saml_validate_url'] = $this->_getServerBaseURL().'samlValidate';
+                break;
+            }
+        }
+
+        $url = $this->_buildQueryUrl($this->_server['saml_validate_url'], 'TARGET='.urlencode($this->getURL()));
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+    /**
+     * This method is used to retrieve the proxy validating URL of the CAS server.
+     *
+     * @return string proxyValidate URL.
+     */
+    public function getServerProxyValidateURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is build only when needed
+        if ( empty($this->_server['proxy_validate_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['proxy_validate_url'] = '';
+                break;
+            case CAS_VERSION_2_0:
+                $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'proxyValidate';
+                break;
+            }
+        }
+        $url = $this->_buildQueryUrl($this->_server['proxy_validate_url'], 'service='.urlencode($this->getURL()));
+        phpCAS::traceEnd($url);
+        return $url;
+    }
+
+
+    /**
+     * This method is used to retrieve the proxy URL of the CAS server.
+     *
+     * @return  string proxy URL.
+     */
+    public function getServerProxyURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['proxy_url']) ) {
+            switch ($this->getServerVersion()) {
+            case CAS_VERSION_1_0:
+                $this->_server['proxy_url'] = '';
+                break;
+            case CAS_VERSION_2_0:
+                $this->_server['proxy_url'] = $this->_getServerBaseURL().'proxy';
+                break;
+            }
+        }
+        return $this->_server['proxy_url'];
+    }
+
+    /**
+     * This method is used to retrieve the logout URL of the CAS server.
+     *
+     * @return string logout URL.
+     */
+    public function getServerLogoutURL()
+    {
+        // the URL is build only when needed
+        if ( empty($this->_server['logout_url']) ) {
+            $this->_server['logout_url'] = $this->_getServerBaseURL().'logout';
+        }
+        return $this->_server['logout_url'];
+    }
+
+    /**
+     * This method sets the logout URL of the CAS server.
+     *
+     * @param string $url the logout URL
+     *
+     * @return string logout url
+     */
+    public function setServerLogoutURL($url)
+    {
+        return $this->_server['logout_url'] = $url;
+    }
+
+    /**
+     * An array to store extra curl options.
+     */
+    private $_curl_options = array();
+
+    /**
+     * This method is used to set additional user curl options.
+     *
+     * @param string $key   name of the curl option
+     * @param string $value value of the curl option
+     *
+     * @return void
+     */
+    public function setExtraCurlOption($key, $value)
+    {
+        $this->_curl_options[$key] = $value;
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  Change the internal behaviour of phpcas
+    // ########################################################################
+
+    /**
+     * @addtogroup internalBehave
+     * @{
+     */
+
+    /**
+     * The class to instantiate for making web requests in readUrl().
+     * The class specified must implement the CAS_Request_RequestInterface.
+     * By default CAS_Request_CurlRequest is used, but this may be overridden to
+     * supply alternate request mechanisms for testing.
+     */
+    private $_requestImplementation = 'CAS_Request_CurlRequest';
+
+    /**
+     * Override the default implementation used to make web requests in readUrl().
+     * This class must implement the CAS_Request_RequestInterface.
+     *
+     * @param string $className name of the RequestImplementation class
+     *
+     * @return void
+     */
+    public function setRequestImplementation ($className)
+    {
+        $obj = new $className;
+        if (!($obj instanceof CAS_Request_RequestInterface)) {
+            throw new CAS_InvalidArgumentException('$className must implement the CAS_Request_RequestInterface');
+        }
+        $this->_requestImplementation = $className;
+    }
+
+    /**
+     * @var boolean $_clearTicketsFromUrl; If true, phpCAS will clear session
+     * tickets from the URL after a successful authentication.
+     */
+    private $_clearTicketsFromUrl = true;
+
+    /**
+     * Configure the client to not send redirect headers and call exit() on
+     * authentication success. The normal redirect is used to remove the service
+     * ticket from the client's URL, but for running unit tests we need to
+     * continue without exiting.
+     *
+     * Needed for testing authentication
+     *
+     * @return void
+     */
+    public function setNoClearTicketsFromUrl ()
+    {
+        $this->_clearTicketsFromUrl = false;
+    }
+
+    /**
+     * @var callback $_postAuthenticateCallbackFunction;
+     */
+    private $_postAuthenticateCallbackFunction = null;
+
+    /**
+     * @var array $_postAuthenticateCallbackArgs;
+     */
+    private $_postAuthenticateCallbackArgs = array();
+
+    /**
+     * Set a callback function to be run when a user authenticates.
+     *
+     * The callback function will be passed a $logoutTicket as its first parameter,
+     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an
+     * opaque string that can be used to map a session-id to the logout request
+     * in order to support single-signout in applications that manage their own
+     * sessions (rather than letting phpCAS start the session).
+     *
+     * phpCAS::forceAuthentication() will always exit and forward client unless
+     * they are already authenticated. To perform an action at the moment the user
+     * logs in (such as registering an account, performing logging, etc), register
+     * a callback function here.
+     *
+     * @param string $function       callback function to call
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public function setPostAuthenticateCallback ($function, array $additionalArgs = array())
+    {
+        $this->_postAuthenticateCallbackFunction = $function;
+        $this->_postAuthenticateCallbackArgs = $additionalArgs;
+    }
+
+    /**
+     * @var callback $_signoutCallbackFunction;
+     */
+    private $_signoutCallbackFunction = null;
+
+    /**
+     * @var array $_signoutCallbackArgs;
+     */
+    private $_signoutCallbackArgs = array();
+
+    /**
+     * Set a callback function to be run when a single-signout request is received.
+     *
+     * The callback function will be passed a $logoutTicket as its first parameter,
+     * followed by any $additionalArgs you pass. The $logoutTicket parameter is an
+     * opaque string that can be used to map a session-id to the logout request in
+     * order to support single-signout in applications that manage their own sessions
+     * (rather than letting phpCAS start and destroy the session).
+     *
+     * @param string $function       callback function to call
+     * @param array  $additionalArgs optional array of arguments
+     *
+     * @return void
+     */
+    public function setSingleSignoutCallback ($function, array $additionalArgs = array())
+    {
+        $this->_signoutCallbackFunction = $function;
+        $this->_signoutCallbackArgs = $additionalArgs;
+    }
+
+    // ########################################################################
+    //  Methods for supplying code-flow feedback to integrators.
+    // ########################################################################
+
+    /**
+     * Mark the caller of authentication. This will help client integraters determine
+     * problems with their code flow if they call a function such as getUser() before
+     * authentication has occurred.
+     *
+     * @param bool $auth True if authentication was successful, false otherwise.
+     *
+     * @return null
+     */
+    public function markAuthenticationCall ($auth)
+    {
+        // store where the authentication has been checked and the result
+        $dbg = debug_backtrace();
+        $this->_authentication_caller = array (
+            'file' => $dbg[1]['file'],
+            'line' => $dbg[1]['line'],
+            'method' => $dbg[1]['class'] . '::' . $dbg[1]['function'],
+            'result' => (boolean)$auth
+        );
+    }
+    private $_authentication_caller;
+
+    /**
+     * Answer true if authentication has been checked.
+     *
+     * @return bool
+     */
+    public function wasAuthenticationCalled ()
+    {
+        return !empty($this->_authentication_caller);
+    }
+
+    /**
+     * Answer the result of the authentication call.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return bool
+     */
+    public function wasAuthenticationCallSuccessful ()
+    {
+        if (empty($this->_authentication_caller)) {
+            throw new CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
+        }
+        return $this->_authentication_caller['result'];
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return array Keys are 'file', 'line', and 'method'
+     */
+    public function getAuthenticationCallerFile ()
+    {
+        if (empty($this->_authentication_caller)) {
+            throw new CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
+        }
+        return $this->_authentication_caller['file'];
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return array Keys are 'file', 'line', and 'method'
+     */
+    public function getAuthenticationCallerLine ()
+    {
+        if (empty($this->_authentication_caller)) {
+            throw new CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
+        }
+        return $this->_authentication_caller['line'];
+    }
+
+    /**
+     * Answer information about the authentication caller.
+     *
+     * Throws a CAS_OutOfSequenceException if wasAuthenticationCalled() is false
+     * and markAuthenticationCall() didn't happen.
+     *
+     * @return array Keys are 'file', 'line', and 'method'
+     */
+    public function getAuthenticationCallerMethod ()
+    {
+        if (empty($this->_authentication_caller)) {
+            throw new CAS_OutOfSequenceException('markAuthenticationCall() hasn\'t happened.');
+        }
+        return $this->_authentication_caller['method'];
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+    /**
+    * @addtogroup internalConfig
+    * @{
+    */
+
+    /**
+     * CAS_Client constructor.
+     *
+     * @param string $server_version  the version of the CAS server
+     * @param bool   $proxy           true if the CAS client is a CAS proxy
+     * @param string $server_hostname the hostname of the CAS server
+     * @param int    $server_port     the port the CAS server is running on
+     * @param string $server_uri      the URI the CAS server is responding on
+     * @param bool   $changeSessionID Allow phpCAS to change the session_id (Single Sign Out/handleLogoutRequests is based on that change)
+     *
+     * @return a newly created CAS_Client object
+     */
+    public function __construct(
+        $server_version,
+        $proxy,
+        $server_hostname,
+        $server_port,
+        $server_uri,
+        $changeSessionID = true
+    ) {
+
+        phpCAS::traceBegin();
+
+        $this->_setChangeSessionID($changeSessionID); // true : allow to change the session_id(), false session_id won't be change and logout won't be handle because of that
+
+        // skip Session Handling for logout requests and if don't want it'
+        if (session_id()=="" && !$this->_isLogoutRequest()) {
+            phpCAS :: trace("Starting a new session");
+            session_start();
+        }
+
+        // are we in proxy mode ?
+        $this->_proxy = $proxy;
+
+        // Make cookie handling available.
+        if ($this->isProxy()) {
+            if (!isset($_SESSION['phpCAS'])) {
+                $_SESSION['phpCAS'] = array();
+            }
+            if (!isset($_SESSION['phpCAS']['service_cookies'])) {
+                $_SESSION['phpCAS']['service_cookies'] = array();
+            }
+            $this->_serviceCookieJar = new CAS_CookieJar($_SESSION['phpCAS']['service_cookies']);
+        }
+
+        //check version
+        switch ($server_version) {
+        case CAS_VERSION_1_0:
+            if ( $this->isProxy() ) {
+                phpCAS::error(
+                    'CAS proxies are not supported in CAS '.$server_version
+                );
+            }
+            break;
+        case CAS_VERSION_2_0:
+            break;
+        case SAML_VERSION_1_1:
+            break;
+        default:
+            phpCAS::error(
+                'this version of CAS (`'.$server_version
+                .'\') is not supported by phpCAS '.phpCAS::getVersion()
+            );
+        }
+        $this->_server['version'] = $server_version;
+
+        // check hostname
+        if ( empty($server_hostname)
+            || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/', $server_hostname)
+        ) {
+            phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
+        }
+        $this->_server['hostname'] = $server_hostname;
+
+        // check port
+        if ( $server_port == 0
+            || !is_int($server_port)
+        ) {
+            phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
+        }
+        $this->_server['port'] = $server_port;
+
+        // check URI
+        if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/', $server_uri) ) {
+            phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
+        }
+        // add leading and trailing `/' and remove doubles
+        $server_uri = preg_replace('/\/\//', '/', '/'.$server_uri.'/');
+        $this->_server['uri'] = $server_uri;
+
+        // set to callback mode if PgtIou and PgtId CGI GET parameters are provided
+        if ( $this->isProxy() ) {
+            $this->_setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
+        }
+
+        if ( $this->_isCallbackMode() ) {
+            //callback mode: check that phpCAS is secured
+            if ( !$this->_isHttps() ) {
+                phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
+            }
+        } else {
+            //normal mode: get ticket and remove it from CGI parameters for
+            // developers
+            $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
+            if (preg_match('/^[SP]T-/', $ticket) ) {
+                phpCAS::trace('Ticket \''.$ticket.'\' found');
+                $this->setTicket($ticket);
+                unset($_GET['ticket']);
+            } else if ( !empty($ticket) ) {
+                //ill-formed ticket, halt
+                phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
+            }
+
+        }
+        phpCAS::traceEnd();
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                           Session Handling                         XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalConfig
+     * @{
+     */
+
+
+    /**
+     * A variable to whether phpcas will use its own session handling. Default = true
+     * @hideinitializer
+     */
+    private $_change_session_id = true;
+
+    /**
+     * Set a parameter whether to allow phpCas to change session_id
+     *
+     * @param bool $allowed allow phpCas to change session_id
+     *
+     * @return void
+     */
+    private function _setChangeSessionID($allowed)
+    {
+        $this->_change_session_id = $allowed;
+    }
+
+    /**
+     * Get whether phpCas is allowed to change session_id
+     *
+     * @return bool
+     */
+    public function getChangeSessionID()
+    {
+        return $this->_change_session_id;
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                           AUTHENTICATION                           XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalAuthentication
+     * @{
+     */
+
+    /**
+     * The Authenticated user. Written by CAS_Client::_setUser(), read by
+     * CAS_Client::getUser().
+     *
+     * @hideinitializer
+     */
+    private $_user = '';
+
+    /**
+     * This method sets the CAS user's login name.
+     *
+     * @param string $user the login name of the authenticated user.
+     *
+     * @return void
+     */
+    private function _setUser($user)
+    {
+        $this->_user = $user;
+    }
+
+    /**
+     * This method returns the CAS user's login name.
+     *
+     * @return string the login name of the authenticated user
+     *
+     * @warning should be called only after CAS_Client::forceAuthentication() or
+     * CAS_Client::isAuthenticated(), otherwise halt with an error.
+     */
+    public function getUser()
+    {
+        if ( empty($this->_user) ) {
+            phpCAS::error(
+                'this method should be used only after '.__CLASS__
+                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
+            );
+        }
+        return $this->_user;
+    }
+
+    /**
+     * The Authenticated users attributes. Written by
+     * CAS_Client::setAttributes(), read by CAS_Client::getAttributes().
+     * @attention client applications should use phpCAS::getAttributes().
+     *
+     * @hideinitializer
+     */
+    private $_attributes = array();
+
+    /**
+     * Set an array of attributes
+     *
+     * @param array $attributes a key value array of attributes
+     *
+     * @return void
+     */
+    public function setAttributes($attributes)
+    {
+        $this->_attributes = $attributes;
+    }
+
+    /**
+     * Get an key values arry of attributes
+     *
+     * @return arry of attributes
+     */
+    public function getAttributes()
+    {
+        if ( empty($this->_user) ) {
+            // if no user is set, there shouldn't be any attributes also...
+            phpCAS::error(
+                'this method should be used only after '.__CLASS__
+                .'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'
+            );
+        }
+        return $this->_attributes;
+    }
+
+    /**
+     * Check whether attributes are available
+     *
+     * @return bool attributes available
+     */
+    public function hasAttributes()
+    {
+        return !empty($this->_attributes);
+    }
+    /**
+     * Check whether a specific attribute with a name is available
+     *
+     * @param string $key name of attribute
+     *
+     * @return bool is attribute available
+     */
+    public function hasAttribute($key)
+    {
+        return (is_array($this->_attributes)
+            && array_key_exists($key, $this->_attributes));
+    }
+
+    /**
+     * Get a specific attribute by name
+     *
+     * @param string $key name of attribute
+     *
+     * @return string attribute values
+     */
+    public function getAttribute($key)
+    {
+        if ($this->hasAttribute($key)) {
+            return $this->_attributes[$key];
+        }
+    }
+
+    /**
+     * This method is called to renew the authentication of the user
+     * If the user is authenticated, renew the connection
+     * If not, redirect to CAS
+     *
+     * @return  void
+     */
+    public function renewAuthentication()
+    {
+        phpCAS::traceBegin();
+        // Either way, the user is authenticated by CAS
+        if (isset( $_SESSION['phpCAS']['auth_checked'])) {
+            unset($_SESSION['phpCAS']['auth_checked']);
+        }
+        if ( $this->isAuthenticated() ) {
+            phpCAS::trace('user already authenticated; renew');
+            $this->redirectToCas(false, true);
+        } else {
+            $this->redirectToCas();
+        }
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method is called to be sure that the user is authenticated. When not
+     * authenticated, halt by redirecting to the CAS server; otherwise return true.
+     *
+     * @return true when the user is authenticated; otherwise halt.
+     */
+    public function forceAuthentication()
+    {
+        phpCAS::traceBegin();
+
+        if ( $this->isAuthenticated() ) {
+            // the user is authenticated, nothing to be done.
+            phpCAS::trace('no need to authenticate');
+            $res = true;
+        } else {
+            // the user is not authenticated, redirect to the CAS server
+            if (isset($_SESSION['phpCAS']['auth_checked'])) {
+                unset($_SESSION['phpCAS']['auth_checked']);
+            }
+            $this->redirectToCas(false/* no gateway */);
+            // never reached
+            $res = false;
+        }
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * An integer that gives the number of times authentication will be cached
+     * before rechecked.
+     *
+     * @hideinitializer
+     */
+    private $_cache_times_for_auth_recheck = 0;
+
+    /**
+     * Set the number of times authentication will be cached before rechecked.
+     *
+     * @param int $n number of times to wait for a recheck
+     *
+     * @return void
+     */
+    public function setCacheTimesForAuthRecheck($n)
+    {
+        $this->_cache_times_for_auth_recheck = $n;
+    }
+
+    /**
+     * This method is called to check whether the user is authenticated or not.
+     *
+     * @return true when the user is authenticated, false when a previous
+     * gateway login failed or  the function will not return if the user is
+     * redirected to the cas server for a gateway login attempt
+     */
+    public function checkAuthentication()
+    {
+        phpCAS::traceBegin();
+        $res = false;
+        if ( $this->isAuthenticated() ) {
+            phpCAS::trace('user is authenticated');
+            /* The 'auth_checked' variable is removed just in case it's set. */
+            unset($_SESSION['phpCAS']['auth_checked']);
+            $res = true;
+        } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
+            // the previous request has redirected the client to the CAS server
+            // with gateway=true
+            unset($_SESSION['phpCAS']['auth_checked']);
+            $res = false;
+        } else {
+            // avoid a check against CAS on every request
+            if (!isset($_SESSION['phpCAS']['unauth_count'])) {
+                $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
+            }
+
+            if (($_SESSION['phpCAS']['unauth_count'] != -2
+                && $this->_cache_times_for_auth_recheck == -1)
+                || ($_SESSION['phpCAS']['unauth_count'] >= 0
+                && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck)
+            ) {
+                $res = false;
+
+                if ($this->_cache_times_for_auth_recheck != -1) {
+                    $_SESSION['phpCAS']['unauth_count']++;
+                    phpCAS::trace(
+                        'user is not authenticated (cached for '
+                        .$_SESSION['phpCAS']['unauth_count'].' times of '
+                        .$this->_cache_times_for_auth_recheck.')'
+                    );
+                } else {
+                    phpCAS::trace('user is not authenticated (cached for until login pressed)');
+                }
+            } else {
+                $_SESSION['phpCAS']['unauth_count'] = 0;
+                $_SESSION['phpCAS']['auth_checked'] = true;
+                phpCAS::trace('user is not authenticated (cache reset)');
+                $this->redirectToCas(true/* gateway */);
+                // never reached
+                $res = false;
+            }
+        }
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method is called to check if the user is authenticated (previously or by
+     * tickets given in the URL).
+     *
+     * @return true when the user is authenticated. Also may redirect to the
+     * same URL without the ticket.
+     */
+    public function isAuthenticated()
+    {
+        phpCAS::traceBegin();
+        $res = false;
+        $validate_url = '';
+        if ( $this->_wasPreviouslyAuthenticated() ) {
+            if ($this->hasTicket()) {
+                // User has a additional ticket but was already authenticated
+                phpCAS::trace('ticket was present and will be discarded, use renewAuthenticate()');
+                if ($this->_clearTicketsFromUrl) {
+                    phpCAS::trace("Prepare redirect to : ".$this->getURL());
+                    header('Location: '.$this->getURL());
+                    flush();
+                    phpCAS::traceExit();
+                    throw new CAS_GracefullTerminationException();
+                } else {
+                    phpCAS::trace('Already authenticated, but skipping ticket clearing since setNoClearTicketsFromUrl() was used.');
+                    $res = true;
+                }
+            } else {
+                // the user has already (previously during the session) been
+                // authenticated, nothing to be done.
+                phpCAS::trace('user was already authenticated, no need to look for tickets');
+                $res = true;
+            }
+        } else {
+            if ($this->hasTicket()) {
+                switch ($this->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    // if a Service Ticket was given, validate it
+                    phpCAS::trace('CAS 1.0 ticket `'.$this->getTicket().'\' is present');
+                    $this->validateCAS10($validate_url, $text_response, $tree_response); // if it fails, it halts
+                    phpCAS::trace('CAS 1.0 ticket `'.$this->getTicket().'\' was validated');
+                    $_SESSION['phpCAS']['user'] = $this->getUser();
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                case CAS_VERSION_2_0:
+                    // if a Proxy Ticket was given, validate it
+                    phpCAS::trace('CAS 2.0 ticket `'.$this->getTicket().'\' is present');
+                    $this->validateCAS20($validate_url, $text_response, $tree_response); // note: if it fails, it halts
+                    phpCAS::trace('CAS 2.0 ticket `'.$this->getTicket().'\' was validated');
+                    if ( $this->isProxy() ) {
+                        $this->_validatePGT($validate_url, $text_response, $tree_response); // idem
+                        phpCAS::trace('PGT `'.$this->_getPGT().'\' was validated');
+                        $_SESSION['phpCAS']['pgt'] = $this->_getPGT();
+                    }
+                    $_SESSION['phpCAS']['user'] = $this->getUser();
+                    if ($this->hasAttributes()) {
+                        $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
+                    }
+                    $proxies = $this->getProxies();
+                    if (!empty($proxies)) {
+                        $_SESSION['phpCAS']['proxies'] = $this->getProxies();
+                    }
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                case SAML_VERSION_1_1:
+                    // if we have a SAML ticket, validate it.
+                    phpCAS::trace('SAML 1.1 ticket `'.$this->getTicket().'\' is present');
+                    $this->validateSA($validate_url, $text_response, $tree_response); // if it fails, it halts
+                    phpCAS::trace('SAML 1.1 ticket `'.$this->getTicket().'\' was validated');
+                    $_SESSION['phpCAS']['user'] = $this->getUser();
+                    $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
+                    $res = true;
+                    $logoutTicket = $this->getTicket();
+                    break;
+                default:
+                    phpCAS::trace('Protocoll error');
+                    break;
+                }
+            } else {
+                // no ticket given, not authenticated
+                phpCAS::trace('no ticket found');
+            }
+            if ($res) {
+                // Mark the auth-check as complete to allow post-authentication
+                // callbacks to make use of phpCAS::getUser() and similar methods
+                $this->markAuthenticationCall($res);
+
+                // call the post-authenticate callback if registered.
+                if ($this->_postAuthenticateCallbackFunction) {
+                    $args = $this->_postAuthenticateCallbackArgs;
+                    array_unshift($args, $logoutTicket);
+                    call_user_func_array($this->_postAuthenticateCallbackFunction, $args);
+                }
+
+                // if called with a ticket parameter, we need to redirect to the
+                // app without the ticket so that CAS-ification is transparent
+                // to the browser (for later POSTS) most of the checks and
+                // errors should have been made now, so we're safe for redirect
+                // without masking error messages. remove the ticket as a
+                // security precaution to prevent a ticket in the HTTP_REFERRER
+                if ($this->_clearTicketsFromUrl) {
+                    phpCAS::trace("Prepare redirect to : ".$this->getURL());
+                    header('Location: '.$this->getURL());
+                    flush();
+                    phpCAS::traceExit();
+                    throw new CAS_GracefullTerminationException();
+                }
+            }
+        }
+
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * This method tells if the current session is authenticated.
+     *
+     * @return true if authenticated based soley on $_SESSION variable
+     */
+    public function isSessionAuthenticated ()
+    {
+        return !empty($_SESSION['phpCAS']['user']);
+    }
+
+    /**
+     * This method tells if the user has already been (previously) authenticated
+     * by looking into the session variables.
+     *
+     * @note This function switches to callback mode when needed.
+     *
+     * @return true when the user has already been authenticated; false otherwise.
+     */
+    private function _wasPreviouslyAuthenticated()
+    {
+        phpCAS::traceBegin();
+
+        if ( $this->_isCallbackMode() ) {
+            // Rebroadcast the pgtIou and pgtId to all nodes
+            if ($this->_rebroadcast&&!isset($_POST['rebroadcast'])) {
+                $this->_rebroadcast(self::PGTIOU);
+            }
+            $this->_callback();
+        }
+
+        $auth = false;
+
+        if ( $this->isProxy() ) {
+            // CAS proxy: username and PGT must be present
+            if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
+                // authentication already done
+                $this->_setUser($_SESSION['phpCAS']['user']);
+                if (isset($_SESSION['phpCAS']['attributes'])) {
+                    $this->setAttributes($_SESSION['phpCAS']['attributes']);
+                }
+                $this->_setPGT($_SESSION['phpCAS']['pgt']);
+                phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\'');
+
+                // Include the list of proxies
+                if (isset($_SESSION['phpCAS']['proxies'])) {
+                    $this->_setProxies($_SESSION['phpCAS']['proxies']);
+                    phpCAS::trace('proxies = "'.implode('", "', $_SESSION['phpCAS']['proxies']).'"');
+                }
+
+                $auth = true;
+            } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
+                // these two variables should be empty or not empty at the same time
+                phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
+                // unset all tickets to enforce authentication
+                unset($_SESSION['phpCAS']);
+                $this->setTicket('');
+            } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
+                // these two variables should be empty or not empty at the same time
+                phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty');
+                // unset all tickets to enforce authentication
+                unset($_SESSION['phpCAS']);
+                $this->setTicket('');
+            } else {
+                phpCAS::trace('neither user nor PGT found');
+            }
+        } else {
+            // `simple' CAS client (not a proxy): username must be present
+            if ( $this->isSessionAuthenticated() ) {
+                // authentication already done
+                $this->_setUser($_SESSION['phpCAS']['user']);
+                if (isset($_SESSION['phpCAS']['attributes'])) {
+                    $this->setAttributes($_SESSION['phpCAS']['attributes']);
+                }
+                phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\'');
+
+                // Include the list of proxies
+                if (isset($_SESSION['phpCAS']['proxies'])) {
+                    $this->_setProxies($_SESSION['phpCAS']['proxies']);
+                    phpCAS::trace('proxies = "'.implode('", "', $_SESSION['phpCAS']['proxies']).'"');
+                }
+
+                $auth = true;
+            } else {
+                phpCAS::trace('no user found');
+            }
+        }
+
+        phpCAS::traceEnd($auth);
+        return $auth;
+    }
+
+    /**
+     * This method is used to redirect the client to the CAS server.
+     * It is used by CAS_Client::forceAuthentication() and
+     * CAS_Client::checkAuthentication().
+     *
+     * @param bool $gateway true to check authentication, false to force it
+     * @param bool $renew   true to force the authentication with the CAS server
+     *
+     * @return void
+     */
+    public function redirectToCas($gateway=false,$renew=false)
+    {
+        phpCAS::traceBegin();
+        $cas_url = $this->getServerLoginURL($gateway, $renew);
+        if (php_sapi_name() === 'cli') {
+            @header('Location: '.$cas_url);
+        } else {
+            header('Location: '.$cas_url);
+        }
+        phpCAS::trace("Redirect to : ".$cas_url);
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getAuthenticationWanted());
+        printf('<p>'. $lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+
+    /**
+     * This method is used to logout from CAS.
+     *
+     * @param array $params an array that contains the optional url and service
+     * parameters that will be passed to the CAS server
+     *
+     * @return void
+     */
+    public function logout($params)
+    {
+        phpCAS::traceBegin();
+        $cas_url = $this->getServerLogoutURL();
+        $paramSeparator = '?';
+        if (isset($params['url'])) {
+            $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']);
+            $paramSeparator = '&';
+        }
+        if (isset($params['service'])) {
+            $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']);
+        }
+        header('Location: '.$cas_url);
+        phpCAS::trace("Prepare redirect to : ".$cas_url);
+
+        session_unset();
+        session_destroy();
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getLogout());
+        printf('<p>'.$lang->getShouldHaveBeenRedirected(). '</p>', $cas_url);
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+    /**
+     * Check of the current request is a logout request
+     *
+     * @return bool is logout request.
+     */
+    private function _isLogoutRequest()
+    {
+        return !empty($_POST['logoutRequest']);
+    }
+
+    /**
+     * This method handles logout requests.
+     *
+     * @param bool $check_client    true to check the client bofore handling
+     * the request, false not to perform any access control. True by default.
+     * @param bool $allowed_clients an array of host names allowed to send
+     * logout requests.
+     *
+     * @return void
+     */
+    public function handleLogoutRequests($check_client=true, $allowed_clients=false)
+    {
+        phpCAS::traceBegin();
+        if (!$this->_isLogoutRequest()) {
+            phpCAS::trace("Not a logout request");
+            phpCAS::traceEnd();
+            return;
+        }
+        if (!$this->getChangeSessionID() && is_null($this->_signoutCallbackFunction)) {
+            phpCAS::trace("phpCAS can't handle logout requests if it is not allowed to change session_id.");
+        }
+        phpCAS::trace("Logout requested");
+        $decoded_logout_rq = urldecode($_POST['logoutRequest']);
+        phpCAS::trace("SAML REQUEST: ".$decoded_logout_rq);
+        $allowed = false;
+        if ($check_client) {
+            if (!$allowed_clients) {
+                $allowed_clients = array( $this->_getServerHostname() );
+            }
+            $client_ip = $_SERVER['REMOTE_ADDR'];
+            $client = gethostbyaddr($client_ip);
+            phpCAS::trace("Client: ".$client."/".$client_ip);
+            foreach ($allowed_clients as $allowed_client) {
+                if (($client == $allowed_client) or ($client_ip == $allowed_client)) {
+                    phpCAS::trace("Allowed client '".$allowed_client."' matches, logout request is allowed");
+                    $allowed = true;
+                    break;
+                } else {
+                    phpCAS::trace("Allowed client '".$allowed_client."' does not match");
+                }
+            }
+        } else {
+            phpCAS::trace("No access control set");
+            $allowed = true;
+        }
+        // If Logout command is permitted proceed with the logout
+        if ($allowed) {
+            phpCAS::trace("Logout command allowed");
+            // Rebroadcast the logout request
+            if ($this->_rebroadcast && !isset($_POST['rebroadcast'])) {
+                $this->_rebroadcast(self::LOGOUT);
+            }
+            // Extract the ticket from the SAML Request
+            preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3);
+            $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|', '', $tick[0][0]);
+            $ticket2logout = preg_replace('|</samlp:SessionIndex>|', '', $wrappedSamlSessionIndex);
+            phpCAS::trace("Ticket to logout: ".$ticket2logout);
+
+            // call the post-authenticate callback if registered.
+            if ($this->_signoutCallbackFunction) {
+                $args = $this->_signoutCallbackArgs;
+                array_unshift($args, $ticket2logout);
+                call_user_func_array($this->_signoutCallbackFunction, $args);
+            }
+
+            // If phpCAS is managing the session_id, destroy session thanks to session_id.
+            if ($this->getChangeSessionID()) {
+                $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket2logout);
+                phpCAS::trace("Session id: ".$session_id);
+
+                // destroy a possible application session created before phpcas
+                if (session_id() !== "") {
+                    session_unset();
+                    session_destroy();
+                }
+                // fix session ID
+                session_id($session_id);
+                $_COOKIE[session_name()]=$session_id;
+                $_GET[session_name()]=$session_id;
+
+                // Overwrite session
+                session_start();
+                session_unset();
+                session_destroy();
+                phpCAS::trace("Session ". $session_id . " destroyed");
+            }
+        } else {
+            phpCAS::error("Unauthorized logout request from client '".$client."'");
+            phpCAS::trace("Unauthorized logout request from client '".$client."'");
+        }
+        flush();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  ST
+    // ########################################################################
+    /**
+    * @addtogroup internalBasic
+    * @{
+    */
+
+    /**
+     * The Ticket provided in the URL of the request if present
+     * (empty otherwise). Written by CAS_Client::CAS_Client(), read by
+     * CAS_Client::getTicket() and CAS_Client::_hasPGT().
+     *
+     * @hideinitializer
+     */
+    private $_ticket = '';
+
+    /**
+     * This method returns the Service Ticket provided in the URL of the request.
+     *
+     * @return string service ticket.
+     */
+    public  function getTicket()
+    {
+        return $this->_ticket;
+    }
+
+    /**
+     * This method stores the Service Ticket.
+     *
+     * @param string $st The Service Ticket.
+     *
+     * @return void
+     */
+    public function setTicket($st)
+    {
+        $this->_ticket = $st;
+    }
+
+    /**
+     * This method tells if a Service Ticket was stored.
+     *
+     * @return bool if a Service Ticket has been stored.
+     */
+    public function hasTicket()
+    {
+        return !empty($this->_ticket);
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  ST VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalBasic
+    * @{
+    */
+
+    /**
+     * the certificate of the CAS server CA.
+     *
+     * @hideinitializer
+     */
+    private $_cas_server_ca_cert = null;
+
+
+    /**\r
+     * validate CN of the CAS server certificate\r
+     *\r
+     * @hideinitializer\r
+     */\r
+    private $_cas_server_cn_validate = true;
+
+    /**
+     * Set to true not to validate the CAS server.
+     *
+     * @hideinitializer
+     */
+    private $_no_cas_server_validation = false;
+
+
+    /**
+     * Set the CA certificate of the CAS server.
+     *
+     * @param string $cert        the PEM certificate file name of the CA that emited
+     * the cert of the server
+     * @param bool   $validate_cn valiate CN of the CAS server certificate
+     *
+     * @return void
+     */
+    public function setCasServerCACert($cert, $validate_cn)
+    {
+        $this->_cas_server_ca_cert = $cert;
+        $this->_cas_server_cn_validate = $validate_cn;
+    }
+
+    /**
+     * Set no SSL validation for the CAS server.
+     *
+     * @return void
+     */
+    public function setNoCasServerValidation()
+    {
+        $this->_no_cas_server_validation = true;
+    }
+
+    /**
+     * This method is used to validate a CAS 1,0 ticket; halt on failure, and
+     * sets $validate_url, $text_reponse and $tree_response on success.
+     *
+     * @param string &$validate_url  reference to the the URL of the request to
+     * the CAS server.
+     * @param string &$text_response reference to the response of the CAS
+     * server, as is (XML text).
+     * @param string &$tree_response reference to the response of the CAS
+     * server, as a DOM XML tree.
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     */
+    public function validateCAS10(&$validate_url,&$text_response,&$tree_response)
+    {
+        phpCAS::traceBegin();
+        $result = false;
+        // build the URL to validate the ticket
+        $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getTicket();
+
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
+            throw new CAS_AuthenticationException(
+                $this, 'CAS 1.0 ticket not validated', $validate_url,
+                true/*$no_response*/
+            );
+            $result = false;
+        }
+
+        if (preg_match('/^no\n/', $text_response)) {
+            phpCAS::trace('Ticket has not been validated');
+            throw new CAS_AuthenticationException(
+                $this, 'ST not validated', $validate_url, false/*$no_response*/,
+                false/*$bad_response*/, $text_response
+            );
+            $result = false;
+        } else if (!preg_match('/^yes\n/', $text_response)) {
+            phpCAS::trace('ill-formed response');
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+            $result = false;
+        }
+        // ticket has been validated, extract the user name
+        $arr = preg_split('/\n/', $text_response);
+        $this->_setUser(trim($arr[1]));
+        $result = true;
+
+        if ($result) {
+            $this->_renameSession($this->getTicket());
+        }
+        // at this step, ticket has been validated and $this->_user has been set,
+        phpCAS::traceEnd(true);
+        return true;
+    }
+
+    /** @} */
+
+
+    // ########################################################################
+    //  SAML VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalSAML
+    * @{
+    */
+
+    /**
+     * This method is used to validate a SAML TICKET; halt on failure, and sets
+     * $validate_url, $text_reponse and $tree_response on success. These
+     * parameters are used later by CAS_Client::_validatePGT() for CAS proxies.
+     *
+     * @param string &$validate_url  reference to the the URL of the request to
+     * the CAS server.
+     * @param string &$text_response reference to the response of the CAS
+     * server, as is (XML text).
+     * @param string &$tree_response reference to the response of the CAS
+     * server, as a DOM XML tree.
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     */
+    public function validateSA(&$validate_url,&$text_response,&$tree_response)
+    {
+        phpCAS::traceBegin();
+        $result = false;
+        // build the URL to validate the ticket
+        $validate_url = $this->getServerSamlValidateURL();
+
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
+            throw new CAS_AuthenticationException($this, 'SA not validated', $validate_url, true/*$no_response*/);
+        }
+
+        phpCAS::trace('server version: '.$this->getServerVersion());
+
+        // analyze the result depending on the version
+        switch ($this->getServerVersion()) {
+        case SAML_VERSION_1_1:
+            // create new DOMDocument Object
+            $dom = new DOMDocument();
+            // Fix possible whitspace problems
+            $dom->preserveWhiteSpace = false;
+            // read the response of the CAS server into a DOM object
+            if (!($dom->loadXML($text_response))) {
+                phpCAS::trace('dom->loadXML() failed');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+                $result = false;
+            }
+            // read the root node of the XML tree
+            if (!($tree_response = $dom->documentElement)) {
+                phpCAS::trace('documentElement() failed');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+                $result = false;
+            } else if ( $tree_response->localName != 'Envelope' ) {
+                // insure that tag name is 'Envelope'
+                phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->localName.'\'');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+                $result = false;
+            } else if ($tree_response->getElementsByTagName("NameIdentifier")->length != 0) {
+                // check for the NameIdentifier tag in the SAML response
+                $success_elements = $tree_response->getElementsByTagName("NameIdentifier");
+                phpCAS::trace('NameIdentifier found');
+                $user = trim($success_elements->item(0)->nodeValue);
+                phpCAS::trace('user = `'.$user.'`');
+                $this->_setUser($user);
+                $this->_setSessionAttributes($text_response);
+                $result = true;
+            } else {
+                phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
+                throw new CAS_AuthenticationException(
+                    $this, 'SA not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/,
+                    $text_response
+                );
+                $result = false;
+            }
+        }
+        if ($result) {
+            $this->_renameSession($this->getTicket());
+        }
+        // at this step, ST has been validated and $this->_user has been set,
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+    /**
+     * This method will parse the DOM and pull out the attributes from the SAML
+     * payload and put them into an array, then put the array into the session.
+     *
+     * @param string $text_response the SAML payload.
+     *
+     * @return bool true when successfull and false if no attributes a found
+     */
+    private function _setSessionAttributes($text_response)
+    {
+        phpCAS::traceBegin();
+
+        $result = false;
+
+        $attr_array = array();
+
+        // create new DOMDocument Object
+        $dom = new DOMDocument();
+        // Fix possible whitspace problems
+        $dom->preserveWhiteSpace = false;
+        if (($dom->loadXML($text_response))) {
+            $xPath = new DOMXpath($dom);
+            $xPath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
+            $xPath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
+            $nodelist = $xPath->query("//saml:Attribute");
+
+            if ($nodelist) {
+                foreach ($nodelist as $node) {
+                    $xres = $xPath->query("saml:AttributeValue", $node);
+                    $name = $node->getAttribute("AttributeName");
+                    $value_array = array();
+                    foreach ($xres as $node2) {
+                        $value_array[] = $node2->nodeValue;
+                    }
+                    $attr_array[$name] = $value_array;
+                }
+                // UGent addition...
+                foreach ($attr_array as $attr_key => $attr_value) {
+                    if (count($attr_value) > 1) {
+                        $this->_attributes[$attr_key] = $attr_value;
+                        phpCAS::trace("* " . $attr_key . "=" . $attr_value);
+                    } else {
+                        $this->_attributes[$attr_key] = $attr_value[0];
+                        phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
+                    }
+                }
+                $result = true;
+            } else {
+                phpCAS::trace("SAML Attributes are empty");
+                $result = false;
+            }
+        }
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                     PROXY FEATURES (CAS 2.0)                       XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  PROXYING
+    // ########################################################################
+    /**
+    * @addtogroup internalProxy
+    * @{
+    */
+
+    /**
+     * A boolean telling if the client is a CAS proxy or not. Written by
+     * CAS_Client::CAS_Client(), read by CAS_Client::isProxy().
+     */
+    private $_proxy;
+
+    /**
+     * Handler for managing service cookies.
+     */
+    private $_serviceCookieJar;
+
+    /**
+     * Tells if a CAS client is a CAS proxy or not
+     *
+     * @return true when the CAS client is a CAs proxy, false otherwise
+     */
+    public function isProxy()
+    {
+        return $this->_proxy;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  PGT
+    // ########################################################################
+    /**
+    * @addtogroup internalProxy
+    * @{
+    */
+
+    /**
+     * the Proxy Grnting Ticket given by the CAS server (empty otherwise).
+     * Written by CAS_Client::_setPGT(), read by CAS_Client::_getPGT() and
+     * CAS_Client::_hasPGT().
+     *
+     * @hideinitializer
+     */
+    private $_pgt = '';
+
+    /**
+     * This method returns the Proxy Granting Ticket given by the CAS server.
+     *
+     * @return string the Proxy Granting Ticket.
+     */
+    private function _getPGT()
+    {
+        return $this->_pgt;
+    }
+
+    /**
+     * This method stores the Proxy Granting Ticket.
+     *
+     * @param string $pgt The Proxy Granting Ticket.
+     *
+     * @return void
+     */
+    private function _setPGT($pgt)
+    {
+        $this->_pgt = $pgt;
+    }
+
+    /**
+     * This method tells if a Proxy Granting Ticket was stored.
+     *
+     * @return true if a Proxy Granting Ticket has been stored.
+     */
+    private function _hasPGT()
+    {
+        return !empty($this->_pgt);
+    }
+
+    /** @} */
+
+    // ########################################################################
+    //  CALLBACK MODE
+    // ########################################################################
+    /**
+    * @addtogroup internalCallback
+    * @{
+    */
+    /**
+     * each PHP script using phpCAS in proxy mode is its own callback to get the
+     * PGT back from the CAS server. callback_mode is detected by the constructor
+     * thanks to the GET parameters.
+     */
+
+    /**
+     * a boolean to know if the CAS client is running in callback mode. Written by
+     * CAS_Client::setCallBackMode(), read by CAS_Client::_isCallbackMode().
+     *
+     * @hideinitializer
+     */
+    private $_callback_mode = false;
+
+    /**
+     * This method sets/unsets callback mode.
+     *
+     * @param bool $callback_mode true to set callback mode, false otherwise.
+     *
+     * @return void
+     */
+    private function _setCallbackMode($callback_mode)
+    {
+        $this->_callback_mode = $callback_mode;
+    }
+
+    /**
+     * This method returns true when the CAs client is running i callback mode,
+     * false otherwise.
+     *
+     * @return A boolean.
+     */
+    private function _isCallbackMode()
+    {
+        return $this->_callback_mode;
+    }
+
+    /**
+     * the URL that should be used for the PGT callback (in fact the URL of the
+     * current request without any CGI parameter). Written and read by
+     * CAS_Client::_getCallbackURL().
+     *
+     * @hideinitializer
+     */
+    private $_callback_url = '';
+
+    /**
+     * This method returns the URL that should be used for the PGT callback (in
+     * fact the URL of the current request without any CGI parameter, except if
+     * phpCAS::setFixedCallbackURL() was used).
+     *
+     * @return The callback URL
+     */
+    private function _getCallbackURL()
+    {
+        // the URL is built when needed only
+        if ( empty($this->_callback_url) ) {
+            $final_uri = '';
+            // remove the ticket if present in the URL
+            $final_uri = 'https://';
+            $final_uri .= $this->_getServerUrl();
+            $request_uri = $_SERVER['REQUEST_URI'];
+            $request_uri = preg_replace('/\?.*$/', '', $request_uri);
+            $final_uri .= $request_uri;
+            $this->setCallbackURL($final_uri);
+        }
+        return $this->_callback_url;
+    }
+
+    /**
+     * This method sets the callback url.
+     *
+     * @param string $url url to set callback
+     *
+     * @return void
+     */
+    public function setCallbackURL($url)
+    {
+        return $this->_callback_url = $url;
+    }
+
+    /**
+     * This method is called by CAS_Client::CAS_Client() when running in callback
+     * mode. It stores the PGT and its PGT Iou, prints its output and halts.
+     *
+     * @return void
+     */
+    private function _callback()
+    {
+        phpCAS::traceBegin();
+        if (preg_match('/PGTIOU-[\.\-\w]/', $_GET['pgtIou'])) {
+            if (preg_match('/[PT]GT-[\.\-\w]/', $_GET['pgtId'])) {
+                $this->printHTMLHeader('phpCAS callback');
+                $pgt_iou = $_GET['pgtIou'];
+                $pgt = $_GET['pgtId'];
+                phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
+                echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
+                $this->_storePGT($pgt, $pgt_iou);
+                $this->printHTMLFooter();
+                phpCAS::traceExit("Successfull Callback");
+            } else {
+                phpCAS::error('PGT format invalid' . $_GET['pgtId']);
+                phpCAS::traceExit('PGT format invalid' . $_GET['pgtId']);
+            }
+        } else {
+            phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
+            phpCAS::traceExit('PGTiou format invalid' . $_GET['pgtIou']);
+        }
+
+        // Flush the buffer to prevent from sending anything other then a 200
+        // Success Status back to the CAS Server. The Exception would normally
+        // report as a 500 error.
+        flush();
+        throw new CAS_GracefullTerminationException();
+    }
+
+
+    /** @} */
+
+    // ########################################################################
+    //  PGT STORAGE
+    // ########################################################################
+    /**
+    * @addtogroup internalPGTStorage
+    * @{
+    */
+
+    /**
+     * an instance of a class inheriting of PGTStorage, used to deal with PGT
+     * storage. Created by CAS_Client::setPGTStorageFile(), used
+     * by CAS_Client::setPGTStorageFile() and CAS_Client::_initPGTStorage().
+     *
+     * @hideinitializer
+     */
+    private $_pgt_storage = null;
+
+    /**
+     * This method is used to initialize the storage of PGT's.
+     * Halts on error.
+     *
+     * @return void
+     */
+    private function _initPGTStorage()
+    {
+        // if no SetPGTStorageXxx() has been used, default to file
+        if ( !is_object($this->_pgt_storage) ) {
+            $this->setPGTStorageFile();
+        }
+
+        // initializes the storage
+        $this->_pgt_storage->init();
+    }
+
+    /**
+     * This method stores a PGT. Halts on error.
+     *
+     * @param string $pgt     the PGT to store
+     * @param string $pgt_iou its corresponding Iou
+     *
+     * @return void
+     */
+    private function _storePGT($pgt,$pgt_iou)
+    {
+        // ensure that storage is initialized
+        $this->_initPGTStorage();
+        // writes the PGT
+        $this->_pgt_storage->write($pgt, $pgt_iou);
+    }
+
+    /**
+     * This method reads a PGT from its Iou and deletes the corresponding
+     * storage entry.
+     *
+     * @param string $pgt_iou the PGT Iou
+     *
+     * @return mul The PGT corresponding to the Iou, false when not found.
+     */
+    private function _loadPGT($pgt_iou)
+    {
+        // ensure that storage is initialized
+        $this->_initPGTStorage();
+        // read the PGT
+        return $this->_pgt_storage->read($pgt_iou);
+    }
+
+    /**
+     * This method can be used to set a custom PGT storage object.
+     *
+     * @param CAS_PGTStorage_AbstractStorage $storage a PGT storage object that
+     * inherits from the CAS_PGTStorage_AbstractStorage class
+     *
+     * @return void
+     */
+    public function setPGTStorage($storage)
+    {
+        // check that the storage has not already been set
+        if ( is_object($this->_pgt_storage) ) {
+            phpCAS::error('PGT storage already defined');
+        }
+
+        // check to make sure a valid storage object was specified
+        if ( !($storage instanceof CAS_PGTStorage_AbstractStorage) ) {
+            phpCAS::error('Invalid PGT storage object');
+        }
+
+        // store the PGTStorage object
+        $this->_pgt_storage = $storage;
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests in a database.
+     *
+     * @param string $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string $username       the username to use when connecting to the
+     * database
+     * @param string $password       the password to use when connecting to the
+     * database
+     * @param string $table          the table to use for storing and retrieving
+     * PGTs
+     * @param string $driver_options any driver options to use when connecting
+     * to the database
+     *
+     * @return void
+     */
+    public function setPGTStorageDb($dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
+    {
+        // create the storage object
+        $this->setPGTStorage(new CAS_PGTStorage_Db($this, $dsn_or_pdo, $username, $password, $table, $driver_options));
+    }
+
+    /**
+     * This method is used to tell phpCAS to store the response of the
+     * CAS server to PGT requests onto the filesystem.
+     *
+     * @param string $path the path where the PGT's should be stored
+     *
+     * @return void
+     */
+    public function setPGTStorageFile($path='')
+    {
+        // create the storage object
+        $this->setPGTStorage(new CAS_PGTStorage_File($this, $path));
+    }
+
+
+    // ########################################################################
+    //  PGT VALIDATION
+    // ########################################################################
+    /**
+    * This method is used to validate a PGT; halt on failure.
+    *
+    * @param string &$validate_url the URL of the request to the CAS server.
+    * @param string $text_response the response of the CAS server, as is
+    * (XML text); result of CAS_Client::validateCAS10() or CAS_Client::validateCAS20().
+    * @param string $tree_response the response of the CAS server, as a DOM XML
+    * tree; result of CAS_Client::validateCAS10() or CAS_Client::validateCAS20().
+    *
+    * @return bool true when successfull and issue a CAS_AuthenticationException
+    * and false on an error
+    */
+    private function _validatePGT(&$validate_url,$text_response,$tree_response)
+    {
+        phpCAS::traceBegin();
+        if ( $tree_response->getElementsByTagName("proxyGrantingTicket")->length == 0) {
+            phpCAS::trace('<proxyGrantingTicket> not found');
+            // authentication succeded, but no PGT Iou was transmitted
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket validated but no PGT Iou transmitted',
+                $validate_url, false/*$no_response*/, false/*$bad_response*/,
+                $text_response
+            );
+        } else {
+            // PGT Iou transmitted, extract it
+            $pgt_iou = trim($tree_response->getElementsByTagName("proxyGrantingTicket")->item(0)->nodeValue);
+            if (preg_match('/PGTIOU-[\.\-\w]/', $pgt_iou)) {
+                $pgt = $this->_loadPGT($pgt_iou);
+                if ( $pgt == false ) {
+                    phpCAS::trace('could not load PGT');
+                    throw new CAS_AuthenticationException(
+                        $this, 'PGT Iou was transmitted but PGT could not be retrieved',
+                        $validate_url, false/*$no_response*/,
+                        false/*$bad_response*/, $text_response
+                    );
+                }
+                $this->_setPGT($pgt);
+            } else {
+                phpCAS::trace('PGTiou format error');
+                throw new CAS_AuthenticationException(
+                    $this, 'PGT Iou was transmitted but has wrong format',
+                    $validate_url, false/*$no_response*/, false/*$bad_response*/,
+                    $text_response
+                );
+            }
+        }
+        phpCAS::traceEnd(true);
+        return true;
+    }
+
+    // ########################################################################
+    //  PGT VALIDATION
+    // ########################################################################
+
+    /**
+     * This method is used to retrieve PT's from the CAS server thanks to a PGT.
+     *
+     * @param string $target_service the service to ask for with the PT.
+     * @param string &$err_code      an error code (PHPCAS_SERVICE_OK on success).
+     * @param string &$err_msg       an error message (empty on success).
+     *
+     * @return a Proxy Ticket, or false on error.
+     */
+    public function retrievePT($target_service,&$err_code,&$err_msg)
+    {
+        phpCAS::traceBegin();
+
+        // by default, $err_msg is set empty and $pt to true. On error, $pt is
+        // set to false and $err_msg to an error message. At the end, if $pt is false
+        // and $error_msg is still empty, it is set to 'invalid response' (the most
+        // commonly encountered error).
+        $err_msg = '';
+
+        // build the URL to retrieve the PT
+        $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->_getPGT();
+
+        // open and read the URL
+        if ( !$this->_readURL($cas_url, $headers, $cas_response, $err_msg) ) {
+            phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
+            $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
+            $err_msg = 'could not retrieve PT (no response from the CAS server)';
+            phpCAS::traceEnd(false);
+            return false;
+        }
+
+        $bad_response = false;
+
+        if ( !$bad_response ) {
+            // create new DOMDocument object
+            $dom = new DOMDocument();
+            // Fix possible whitspace problems
+            $dom->preserveWhiteSpace = false;
+            // read the response of the CAS server into a DOM object
+            if ( !($dom->loadXML($cas_response))) {
+                phpCAS::trace('dom->loadXML() failed');
+                // read failed
+                $bad_response = true;
+            }
+        }
+
+        if ( !$bad_response ) {
+            // read the root node of the XML tree
+            if ( !($root = $dom->documentElement) ) {
+                phpCAS::trace('documentElement failed');
+                // read failed
+                $bad_response = true;
+            }
+        }
+
+        if ( !$bad_response ) {
+            // insure that tag name is 'serviceResponse'
+            if ( $root->localName != 'serviceResponse' ) {
+                phpCAS::trace('localName failed');
+                // bad root node
+                $bad_response = true;
+            }
+        }
+
+        if ( !$bad_response ) {
+            // look for a proxySuccess tag
+            if ( $root->getElementsByTagName("proxySuccess")->length != 0) {
+                $proxy_success_list = $root->getElementsByTagName("proxySuccess");
+
+                // authentication succeded, look for a proxyTicket tag
+                if ( $proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->length != 0) {
+                    $err_code = PHPCAS_SERVICE_OK;
+                    $err_msg = '';
+                    $pt = trim($proxy_success_list->item(0)->getElementsByTagName("proxyTicket")->item(0)->nodeValue);
+                    phpCAS::trace('original PT: '.trim($pt));
+                    phpCAS::traceEnd($pt);
+                    return $pt;
+                } else {
+                    phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
+                }
+            } else if ($root->getElementsByTagName("proxyFailure")->length != 0) {
+                // look for a proxyFailure tag
+                $proxy_failure_list = $root->getElementsByTagName("proxyFailure");
+
+                // authentication failed, extract the error
+                $err_code = PHPCAS_SERVICE_PT_FAILURE;
+                $err_msg = 'PT retrieving failed (code=`'
+                .$proxy_failure_list->item(0)->getAttribute('code')
+                .'\', message=`'
+                .trim($proxy_failure_list->item(0)->nodeValue)
+                .'\')';
+                phpCAS::traceEnd(false);
+                return false;
+            } else {
+                phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
+            }
+        }
+
+        // at this step, we are sure that the response of the CAS server was
+        // illformed
+        $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
+        $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
+
+        phpCAS::traceEnd(false);
+        return false;
+    }
+
+    /** @} */
+
+    // ########################################################################
+    // READ CAS SERVER ANSWERS
+    // ########################################################################
+
+    /**
+     * @addtogroup internalMisc
+     * @{
+     */
+
+    /**
+     * This method is used to acces a remote URL.
+     *
+     * @param string $url      the URL to access.
+     * @param string &$headers an array containing the HTTP header lines of the
+     * response (an empty array on failure).
+     * @param string &$body    the body of the response, as a string (empty on
+     * failure).
+     * @param string &$err_msg an error message, filled on failure.
+     *
+     * @return true on success, false otherwise (in this later case, $err_msg
+     * contains an error message).
+     */
+    private function _readURL($url, &$headers, &$body, &$err_msg)
+    {
+        phpCAS::traceBegin();
+        $className = $this->_requestImplementation;
+        $request = new $className();
+
+        if (count($this->_curl_options)) {
+            $request->setCurlOptions($this->_curl_options);
+        }
+
+        $request->setUrl($url);
+
+        if (empty($this->_cas_server_ca_cert) && !$this->_no_cas_server_validation) {
+            phpCAS::error('one of the methods phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
+        }
+        if ($this->_cas_server_ca_cert != '') {
+            $request->setSslCaCert($this->_cas_server_ca_cert, $this->_cas_server_cn_validate);
+        }
+
+        // add extra stuff if SAML
+        if ($this->getServerVersion() == SAML_VERSION_1_1) {
+            $request->addHeader("soapaction: http://www.oasis-open.org/committees/security");
+            $request->addHeader("cache-control: no-cache");
+            $request->addHeader("pragma: no-cache");
+            $request->addHeader("accept: text/xml");
+            $request->addHeader("connection: keep-alive");
+            $request->addHeader("content-type: text/xml");
+            $request->makePost();
+            $request->setPostBody($this->_buildSAMLPayload());
+        }
+
+        if ($request->send()) {
+            $headers = $request->getResponseHeaders();
+            $body = $request->getResponseBody();
+            $err_msg = '';
+            phpCAS::traceEnd(true);
+            return true;
+        } else {
+            $headers = '';
+            $body = '';
+            $err_msg = $request->getErrorMessage();
+            phpCAS::traceEnd(false);
+            return false;
+        }
+    }
+
+    /**
+     * This method is used to build the SAML POST body sent to /samlValidate URL.
+     *
+     * @return the SOAP-encased SAMLP artifact (the ticket).
+     */
+    private function _buildSAMLPayload()
+    {
+        phpCAS::traceBegin();
+
+        //get the ticket
+        $sa = $this->getTicket();
+
+        $body=SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST.SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE.SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
+
+        phpCAS::traceEnd($body);
+        return ($body);
+    }
+
+    /** @} **/
+
+    // ########################################################################
+    // ACCESS TO EXTERNAL SERVICES
+    // ########################################################################
+
+    /**
+     * @addtogroup internalProxyServices
+     * @{
+     */
+
+
+    /**
+     * Answer a proxy-authenticated service handler.
+     *
+     * @param string $type The service type. One of:
+     * PHPCAS_PROXIED_SERVICE_HTTP_GET, PHPCAS_PROXIED_SERVICE_HTTP_POST,
+     * PHPCAS_PROXIED_SERVICE_IMAP
+     *
+     * @return CAS_ProxiedService
+     * @throws InvalidArgumentException If the service type is unknown.
+     */
+    public function getProxiedService ($type)
+    {
+        switch ($type) {
+        case PHPCAS_PROXIED_SERVICE_HTTP_GET:
+        case PHPCAS_PROXIED_SERVICE_HTTP_POST:
+            $requestClass = $this->_requestImplementation;
+            $request = new $requestClass();
+            if (count($this->_curl_options)) {
+                $request->setCurlOptions($this->_curl_options);
+            }
+            $proxiedService = new $type($request, $this->_serviceCookieJar);
+            if ($proxiedService instanceof CAS_ProxiedService_Testable) {
+                $proxiedService->setCasClient($this);
+            }
+            return $proxiedService;
+        case PHPCAS_PROXIED_SERVICE_IMAP;
+            $proxiedService = new CAS_ProxiedService_Imap($this->getUser());
+            if ($proxiedService instanceof CAS_ProxiedService_Testable) {
+                $proxiedService->setCasClient($this);
+            }
+            return $proxiedService;
+        default:
+            throw new CAS_InvalidArgumentException("Unknown proxied-service type, $type.");
+        }
+    }
+
+    /**
+     * Initialize a proxied-service handler with the proxy-ticket it should use.
+     *
+     * @param CAS_ProxiedService $proxiedService service handler
+     *
+     * @return void
+     *
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *         The code of the Exception will be one of:
+     *                 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure getting the
+     * url from the proxied service.
+     */
+    public function initializeProxiedService (CAS_ProxiedService $proxiedService)
+    {
+        $url = $proxiedService->getServiceUrl();
+        if (!is_string($url)) {
+            throw new CAS_ProxiedService_Exception("Proxied Service ".get_class($proxiedService)."->getServiceUrl() should have returned a string, returned a ".gettype($url)." instead.");
+        }
+        $pt = $this->retrievePT($url, $err_code, $err_msg);
+        if (!$pt) {
+            throw new CAS_ProxyTicketException($err_msg, $err_code);
+        }
+        $proxiedService->setProxyTicket($pt);
+    }
+
+    /**
+     * This method is used to access an HTTP[S] service.
+     *
+     * @param string $url       the service to access.
+     * @param int    &$err_code an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     * PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$output   the output of the service (also used to give an error
+     * message on failure).
+     *
+     * @return true on success, false otherwise (in this later case, $err_code
+     * gives the reason why it failed and $output contains an error message).
+     */
+    public function serviceWeb($url,&$err_code,&$output)
+    {
+        try {
+            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
+            $service->setUrl($url);
+            $service->send();
+            $output = $service->getResponseBody();
+            $err_code = PHPCAS_SERVICE_OK;
+            return true;
+        } catch (CAS_ProxyTicketException $e) {
+            $err_code = $e->getCode();
+            $output = $e->getMessage();
+            return false;
+        } catch (CAS_ProxiedService_Exception $e) {
+            $lang = $this->getLangObj();
+            $output = sprintf($lang->getServiceUnavailable(), $url, $e->getMessage());
+            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+            return false;
+        }
+    }
+
+    /**
+     * This method is used to access an IMAP/POP3/NNTP service.
+     *
+     * @param string $url        a string giving the URL of the service, including
+     * the mailing box for IMAP URLs, as accepted by imap_open().
+     * @param string $serviceUrl a string giving for CAS retrieve Proxy ticket
+     * @param string $flags      options given to imap_open().
+     * @param int    &$err_code  an error code Possible values are
+     * PHPCAS_SERVICE_OK (on success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+     * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE, PHPCAS_SERVICE_PT_FAILURE,
+     *  PHPCAS_SERVICE_NOT_AVAILABLE.
+     * @param string &$err_msg   an error message on failure
+     * @param string &$pt        the Proxy Ticket (PT) retrieved from the CAS
+     * server to access the URL on success, false on error).
+     *
+     * @return object an IMAP stream on success, false otherwise (in this later
+     *  case, $err_code gives the reason why it failed and $err_msg contains an
+     *  error message).
+     */
+    public function serviceMail($url,$serviceUrl,$flags,&$err_code,&$err_msg,&$pt)
+    {
+        try {
+            $service = $this->getProxiedService(PHPCAS_PROXIED_SERVICE_IMAP);
+            $service->setServiceUrl($serviceUrl);
+            $service->setMailbox($url);
+            $service->setOptions($flags);
+
+            $stream = $service->open();
+            $err_code = PHPCAS_SERVICE_OK;
+            $pt = $service->getImapProxyTicket();
+            return $stream;
+        } catch (CAS_ProxyTicketException $e) {
+            $err_msg = $e->getMessage();
+            $err_code = $e->getCode();
+            $pt = false;
+            return false;
+        } catch (CAS_ProxiedService_Exception $e) {
+            $lang = $this->getLangObj();
+            $err_msg = sprintf(
+                $lang->getServiceUnavailable(),
+                $url,
+                $e->getMessage()
+            );
+            $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
+            $pt = false;
+            return false;
+        }
+    }
+
+    /** @} **/
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    // ########################################################################
+    //  PT
+    // ########################################################################
+    /**
+    * @addtogroup internalService
+    * @{
+    */
+
+    /**
+     * This array will store a list of proxies in front of this application. This
+     * property will only be populated if this script is being proxied rather than
+     * accessed directly.
+     *
+     * It is set in CAS_Client::validateCAS20() and can be read by
+     * CAS_Client::getProxies()
+     *
+     * @access private
+     */
+    private $_proxies = array();
+
+    /**
+     * Answer an array of proxies that are sitting in front of this application.
+     *
+     * This method will only return a non-empty array if we have received and
+     * validated a Proxy Ticket.
+     *
+     * @return array
+     * @access public
+     */
+    public function getProxies()
+    {
+        return $this->_proxies;
+    }
+
+    /**
+     * Set the Proxy array, probably from persistant storage.
+     *
+     * @param array $proxies An array of proxies
+     *
+     * @return void
+     * @access private
+     */
+    private function _setProxies($proxies)
+    {
+        $this->_proxies = $proxies;
+        if (!empty($proxies)) {
+            // For proxy-authenticated requests people are not viewing the URL
+            // directly since the client is another application making a
+            // web-service call.
+            // Because of this, stripping the ticket from the URL is unnecessary
+            // and causes another web-service request to be performed. Additionally,
+            // if session handling on either the client or the server malfunctions
+            // then the subsequent request will not complete successfully.
+            $this->setNoClearTicketsFromUrl();
+        }
+    }
+
+    /**
+     * A container of patterns to be allowed as proxies in front of the cas client.
+     *
+     * @var CAS_ProxyChain_AllowedList
+     */
+    private $_allowed_proxy_chains;
+
+    /**
+     * Answer the CAS_ProxyChain_AllowedList object for this client.
+     *
+     * @return CAS_ProxyChain_AllowedList
+     */
+    public function getAllowedProxyChains ()
+    {
+        if (empty($this->_allowed_proxy_chains)) {
+            $this->_allowed_proxy_chains = new CAS_ProxyChain_AllowedList();
+        }
+        return $this->_allowed_proxy_chains;
+    }
+
+    /** @} */
+    // ########################################################################
+    //  PT VALIDATION
+    // ########################################################################
+    /**
+    * @addtogroup internalProxied
+    * @{
+    */
+
+    /**
+     * This method is used to validate a cas 2.0 ST or PT; halt on failure
+     * Used for all CAS 2.0 validations
+     *
+     * @param string &$validate_url  the url of the reponse
+     * @param string &$text_response the text of the repsones
+     * @param string &$tree_response the domxml tree of the respones
+     *
+     * @return bool true when successfull and issue a CAS_AuthenticationException
+     * and false on an error
+     */
+    public function validateCAS20(&$validate_url,&$text_response,&$tree_response)
+    {
+        phpCAS::traceBegin();
+        phpCAS::trace($text_response);
+        $result = false;
+        // build the URL to validate the ticket
+        if ($this->getAllowedProxyChains()->isProxyingAllowed()) {
+            $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getTicket();
+        } else {
+            $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getTicket();
+        }
+
+        if ( $this->isProxy() ) {
+            // pass the callback url for CAS proxies
+            $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL());
+        }
+
+        // open and read the URL
+        if ( !$this->_readURL($validate_url, $headers, $text_response, $err_msg) ) {
+            phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                true/*$no_response*/
+            );
+            $result = false;
+        }
+
+        // create new DOMDocument object
+        $dom = new DOMDocument();
+        // Fix possible whitspace problems
+        $dom->preserveWhiteSpace = false;
+        // CAS servers should only return data in utf-8
+        $dom->encoding = "utf-8";
+        // read the response of the CAS server into a DOMDocument object
+        if ( !($dom->loadXML($text_response))) {
+            // read failed
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+            $result = false;
+        } else if ( !($tree_response = $dom->documentElement) ) {
+            // read the root node of the XML tree
+            // read failed
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+            $result = false;
+        } else if ($tree_response->localName != 'serviceResponse') {
+            // insure that tag name is 'serviceResponse'
+            // bad root node
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/, $text_response
+            );
+            $result = false;
+        } else if ($tree_response->getElementsByTagName("authenticationSuccess")->length != 0) {
+            // authentication succeded, extract the user name
+            $success_elements = $tree_response->getElementsByTagName("authenticationSuccess");
+            if ( $success_elements->item(0)->getElementsByTagName("user")->length == 0) {
+                // no user specified => error
+                throw new CAS_AuthenticationException(
+                    $this, 'Ticket not validated', $validate_url,
+                    false/*$no_response*/, true/*$bad_response*/, $text_response
+                );
+                $result = false;
+            } else {
+                $this->_setUser(trim($success_elements->item(0)->getElementsByTagName("user")->item(0)->nodeValue));
+                $this->_readExtraAttributesCas20($success_elements);
+                // Store the proxies we are sitting behind for authorization checking
+                $proxyList = array();
+                if ( sizeof($arr = $success_elements->item(0)->getElementsByTagName("proxy")) > 0) {
+                    foreach ($arr as $proxyElem) {
+                        phpCAS::trace("Found Proxy: ".$proxyElem->nodeValue);
+                        $proxyList[] = trim($proxyElem->nodeValue);
+                    }
+                    $this->_setProxies($proxyList);
+                    phpCAS::trace("Storing Proxy List");
+                }
+                // Check if the proxies in front of us are allowed
+                if (!$this->getAllowedProxyChains()->isProxyListAllowed($proxyList)) {
+                    throw new CAS_AuthenticationException(
+                        $this, 'Proxy not allowed', $validate_url,
+                        false/*$no_response*/, true/*$bad_response*/,
+                        $text_response
+                    );
+                    $result = false;
+                } else {
+                    $result = true;
+                }
+            }
+        } else if ( $tree_response->getElementsByTagName("authenticationFailure")->length != 0) {
+            // authentication succeded, extract the error code and message
+            $auth_fail_list = $tree_response->getElementsByTagName("authenticationFailure");
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, false/*$bad_response*/,
+                $text_response,
+                $auth_fail_list->item(0)->getAttribute('code')/*$err_code*/,
+                trim($auth_fail_list->item(0)->nodeValue)/*$err_msg*/
+            );
+            $result = false;
+        } else {
+            throw new CAS_AuthenticationException(
+                $this, 'Ticket not validated', $validate_url,
+                false/*$no_response*/, true/*$bad_response*/,
+                $text_response
+            );
+            $result = false;
+        }
+        if ($result) {
+            $this->_renameSession($this->getTicket());
+        }
+        // at this step, Ticket has been validated and $this->_user has been set,
+
+        phpCAS::traceEnd($result);
+        return $result;
+    }
+
+
+    /**
+     * This method will parse the DOM and pull out the attributes from the XML
+     * payload and put them into an array, then put the array into the session.
+     *
+     * @param string $success_elements payload of the response
+     *
+     * @return bool true when successfull, halt otherwise by calling
+     * CAS_Client::_authError().
+     */
+    private function _readExtraAttributesCas20($success_elements)
+    {
+        phpCAS::traceBegin();
+
+        $extra_attributes = array();
+
+        // "Jasig Style" Attributes:
+        //
+        //     <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+        //             <cas:authenticationSuccess>
+        //                     <cas:user>jsmith</cas:user>
+        //                     <cas:attributes>
+        //                             <cas:attraStyle>RubyCAS</cas:attraStyle>
+        //                             <cas:surname>Smith</cas:surname>
+        //                             <cas:givenName>John</cas:givenName>
+        //                             <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
+        //                             <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
+        //                     </cas:attributes>
+        //                     <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+        //             </cas:authenticationSuccess>
+        //     </cas:serviceResponse>
+        //
+        if ( $success_elements->item(0)->getElementsByTagName("attributes")->length != 0) {
+            $attr_nodes = $success_elements->item(0)->getElementsByTagName("attributes");
+            phpCas :: trace("Found nested jasig style attributes");
+            if ($attr_nodes->item(0)->hasChildNodes()) {
+                // Nested Attributes
+                foreach ($attr_nodes->item(0)->childNodes as $attr_child) {
+                    phpCas :: trace("Attribute [".$attr_child->localName."] = ".$attr_child->nodeValue);
+                    $this->_addAttributeToArray($extra_attributes, $attr_child->localName, $attr_child->nodeValue);
+                }
+            }
+        } else {
+            // "RubyCAS Style" attributes
+            //
+            //         <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+            //                 <cas:authenticationSuccess>
+            //                         <cas:user>jsmith</cas:user>
+            //
+            //                         <cas:attraStyle>RubyCAS</cas:attraStyle>
+            //                         <cas:surname>Smith</cas:surname>
+            //                         <cas:givenName>John</cas:givenName>
+            //                         <cas:memberOf>CN=Staff,OU=Groups,DC=example,DC=edu</cas:memberOf>
+            //                         <cas:memberOf>CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu</cas:memberOf>
+            //
+            //                         <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+            //                 </cas:authenticationSuccess>
+            //         </cas:serviceResponse>
+            //
+            phpCas :: trace("Testing for rubycas style attributes");
+            $childnodes = $success_elements->item(0)->childNodes;
+            foreach ($childnodes as $attr_node) {
+                switch ($attr_node->localName) {
+                case 'user':
+                case 'proxies':
+                case 'proxyGrantingTicket':
+                    continue;
+                default:
+                    if (strlen(trim($attr_node->nodeValue))) {
+                        phpCas :: trace("Attribute [".$attr_node->localName."] = ".$attr_node->nodeValue);
+                        $this->_addAttributeToArray($extra_attributes, $attr_node->localName, $attr_node->nodeValue);
+                    }
+                }
+            }
+        }
+
+        // "Name-Value" attributes.
+        //
+        // Attribute format from these mailing list thread:
+        // http://jasig.275507.n4.nabble.com/CAS-attributes-and-how-they-appear-in-the-CAS-response-td264272.html
+        // Note: This is a less widely used format, but in use by at least two institutions.
+        //
+        //     <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
+        //             <cas:authenticationSuccess>
+        //                     <cas:user>jsmith</cas:user>
+        //
+        //                     <cas:attribute name='attraStyle' value='Name-Value' />
+        //                     <cas:attribute name='surname' value='Smith' />
+        //                     <cas:attribute name='givenName' value='John' />
+        //                     <cas:attribute name='memberOf' value='CN=Staff,OU=Groups,DC=example,DC=edu' />
+        //                     <cas:attribute name='memberOf' value='CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu' />
+        //
+        //                     <cas:proxyGrantingTicket>PGTIOU-84678-8a9d2sfa23casd</cas:proxyGrantingTicket>
+        //             </cas:authenticationSuccess>
+        //     </cas:serviceResponse>
+        //
+        if (!count($extra_attributes) && $success_elements->item(0)->getElementsByTagName("attribute")->length != 0) {
+            $attr_nodes = $success_elements->item(0)->getElementsByTagName("attribute");
+            $firstAttr = $attr_nodes->item(0);
+            if (!$firstAttr->hasChildNodes() && $firstAttr->hasAttribute('name') && $firstAttr->hasAttribute('value')) {
+                phpCas :: trace("Found Name-Value style attributes");
+                // Nested Attributes
+                foreach ($attr_nodes as $attr_node) {
+                    if ($attr_node->hasAttribute('name') && $attr_node->hasAttribute('value')) {
+                        phpCas :: trace("Attribute [".$attr_node->getAttribute('name')."] = ".$attr_node->getAttribute('value'));
+                        $this->_addAttributeToArray($extra_attributes, $attr_node->getAttribute('name'), $attr_node->getAttribute('value'));
+                    }
+                }
+            }
+        }
+
+        $this->setAttributes($extra_attributes);
+        phpCAS::traceEnd();
+        return true;
+    }
+
+    /**
+     * Add an attribute value to an array of attributes.
+     *
+     * @param array  &$attributeArray reference to array
+     * @param string $name            name of attribute
+     * @param string $value           value of attribute
+     *
+     * @return void
+     */
+    private function _addAttributeToArray(array &$attributeArray, $name, $value)
+    {
+        // If multiple attributes exist, add as an array value
+        if (isset($attributeArray[$name])) {
+            // Initialize the array with the existing value
+            if (!is_array($attributeArray[$name])) {
+                $existingValue = $attributeArray[$name];
+                $attributeArray[$name] = array($existingValue);
+            }
+
+            $attributeArray[$name][] = trim($value);
+        } else {
+            $attributeArray[$name] = trim($value);
+        }
+    }
+
+    /** @} */
+
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+    // XX                                                                    XX
+    // XX                               MISC                                 XX
+    // XX                                                                    XX
+    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+    /**
+     * @addtogroup internalMisc
+     * @{
+     */
+
+    // ########################################################################
+    //  URL
+    // ########################################################################
+    /**
+    * the URL of the current request (without any ticket CGI parameter). Written
+    * and read by CAS_Client::getURL().
+    *
+    * @hideinitializer
+    */
+    private $_url = '';
+
+
+    /**
+     * This method sets the URL of the current request
+     *
+     * @param string $url url to set for service
+     *
+     * @return void
+     */
+    public function setURL($url)
+    {
+        $this->_url = $url;
+    }
+
+    /**
+     * This method returns the URL of the current request (without any ticket
+     * CGI parameter).
+     *
+     * @return The URL
+     */
+    public function getURL()
+    {
+        phpCAS::traceBegin();
+        // the URL is built when needed only
+        if ( empty($this->_url) ) {
+            $final_uri = '';
+            // remove the ticket if present in the URL
+            $final_uri = ($this->_isHttps()) ? 'https' : 'http';
+            $final_uri .= '://';
+
+            $final_uri .= $this->_getServerUrl();
+            $request_uri       = explode('?', $_SERVER['REQUEST_URI'], 2);
+            $final_uri         .= $request_uri[0];
+
+            if (isset($request_uri[1]) && $request_uri[1]) {
+                $query_string= $this->_removeParameterFromQueryString('ticket', $request_uri[1]);
+
+                // If the query string still has anything left, append it to the final URI
+                if ($query_string !== '') {
+                    $final_uri .= "?$query_string";
+                }
+            }
+
+            phpCAS::trace("Final URI: $final_uri");
+            $this->setURL($final_uri);
+        }
+        phpCAS::traceEnd($this->_url);
+        return $this->_url;
+    }
+
+
+    /**
+     * Try to figure out the server URL with possible Proxys / Ports etc.
+     *
+     * @return string Server URL with domain:port
+     */
+    private function _getServerUrl()
+    {
+        $server_url = '';
+        if (!empty($_SERVER['HTTP_X_FORWARDED_HOST'])) {
+            // explode the host list separated by comma and use the first host
+            $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']);
+            $server_url = $hosts[0];
+        } else if (!empty($_SERVER['HTTP_X_FORWARDED_SERVER'])) {
+            $server_url = $_SERVER['HTTP_X_FORWARDED_SERVER'];
+        } else {
+            if (empty($_SERVER['SERVER_NAME'])) {
+                $server_url = $_SERVER['HTTP_HOST'];
+            } else {
+                $server_url = $_SERVER['SERVER_NAME'];
+            }
+        }
+        if (!strpos($server_url, ':')) {
+            if (empty($_SERVER['HTTP_X_FORWARDED_PORT'])) {
+                $server_port = $_SERVER['SERVER_PORT'];
+            } else {
+                $server_port = $_SERVER['HTTP_X_FORWARDED_PORT'];
+            }
+
+            if ( ($this->_isHttps() && $server_port!=443)
+                || (!$this->_isHttps() && $server_port!=80)
+            ) {
+                $server_url .= ':';
+                $server_url .= $server_port;
+            }
+        }
+        return $server_url;
+    }
+
+    /**
+     * This method checks to see if the request is secured via HTTPS
+     *
+     * @return bool true if https, false otherwise
+     */
+    private function _isHttps()
+    {
+        if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Removes a parameter from a query string
+     *
+     * @param string $parameterName name of parameter
+     * @param string $queryString   query string
+     *
+     * @return string new query string
+     *
+     * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string
+     */
+    private function _removeParameterFromQueryString($parameterName, $queryString)
+    {
+        $parameterName = preg_quote($parameterName);
+        return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString);
+    }
+
+    /**
+     * This method is used to append query parameters to an url. Since the url
+     * might already contain parameter it has to be detected and to build a proper
+     * URL
+     *
+     * @param string $url   base url to add the query params to
+     * @param string $query params in query form with & separated
+     *
+     * @return url with query params
+     */
+    private function _buildQueryUrl($url, $query)
+    {
+        $url .= (strstr($url, '?') === false) ? '?' : '&';
+        $url .= $query;
+        return $url;
+    }
+
+    /**
+     * Renaming the session
+     *
+     * @param string $ticket name of the ticket
+     *
+     * @return void
+     */
+    private function _renameSession($ticket)
+    {
+        phpCAS::traceBegin();
+        if ($this->getChangeSessionID()) {
+            if (!empty($this->_user)) {
+                $old_session = $_SESSION;
+                session_destroy();
+                // set up a new session, of name based on the ticket
+                $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket);
+                phpCAS :: trace("Session ID: ".$session_id);
+                session_id($session_id);
+                session_start();
+                phpCAS :: trace("Restoring old session vars");
+                $_SESSION = $old_session;
+            } else {
+                phpCAS :: error('Session should only be renamed after successfull authentication');
+            }
+        } else {
+            phpCAS :: trace("Skipping session rename since phpCAS is not handling the session.");
+        }
+        phpCAS::traceEnd();
+    }
+
+
+    // ########################################################################
+    //  AUTHENTICATION ERROR HANDLING
+    // ########################################################################
+    /**
+    * This method is used to print the HTML output when the user was not
+    * authenticated.
+    *
+    * @param string $failure      the failure that occured
+    * @param string $cas_url      the URL the CAS server was asked for
+    * @param bool   $no_response  the response from the CAS server (other
+    * parameters are ignored if true)
+    * @param bool   $bad_response bad response from the CAS server ($err_code
+    * and $err_msg ignored if true)
+    * @param string $cas_response the response of the CAS server
+    * @param int    $err_code     the error code given by the CAS server
+    * @param string $err_msg      the error message given by the CAS server
+    *
+    * @return void
+    */
+    private function _authError(
+        $failure,
+        $cas_url,
+        $no_response,
+        $bad_response='',
+        $cas_response='',
+        $err_code='',
+        $err_msg=''
+    ) {
+        phpCAS::traceBegin();
+        $lang = $this->getLangObj();
+        $this->printHTMLHeader($lang->getAuthenticationFailed());
+        printf($lang->getYouWereNotAuthenticated(), htmlentities($this->getURL()), $_SERVER['SERVER_ADMIN']);
+        phpCAS::trace('CAS URL: '.$cas_url);
+        phpCAS::trace('Authentication failure: '.$failure);
+        if ( $no_response ) {
+            phpCAS::trace('Reason: no response from the CAS server');
+        } else {
+            if ( $bad_response ) {
+                phpCAS::trace('Reason: bad response from the CAS server');
+            } else {
+                switch ($this->getServerVersion()) {
+                case CAS_VERSION_1_0:
+                    phpCAS::trace('Reason: CAS error');
+                    break;
+                case CAS_VERSION_2_0:
+                    if ( empty($err_code) ) {
+                        phpCAS::trace('Reason: no CAS error');
+                    } else {
+                        phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
+                    }
+                    break;
+                }
+            }
+            phpCAS::trace('CAS response: '.$cas_response);
+        }
+        $this->printHTMLFooter();
+        phpCAS::traceExit();
+        throw new CAS_GracefullTerminationException();
+    }
+
+    // ########################################################################
+    //  PGTIOU/PGTID and logoutRequest rebroadcasting
+    // ########################################################################
+
+    /**
+     * Boolean of whether to rebroadcast pgtIou/pgtId and logoutRequest, and
+     * array of the nodes.
+     */
+    private $_rebroadcast = false;
+    private $_rebroadcast_nodes = array();
+
+    /**
+     * Constants used for determining rebroadcast node type.
+     */
+    const HOSTNAME = 0;
+    const IP = 1;
+
+    /**
+     * Determine the node type from the URL.
+     *
+     * @param String $nodeURL The node URL.
+     *
+     * @return string hostname
+     *
+     */
+    private function _getNodeType($nodeURL)
+    {
+        phpCAS::traceBegin();
+        if (preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/", $nodeURL)) {
+            phpCAS::traceEnd(self::IP);
+            return self::IP;
+        } else {
+            phpCAS::traceEnd(self::HOSTNAME);
+            return self::HOSTNAME;
+        }
+    }
+
+    /**
+     * Store the rebroadcast node for pgtIou/pgtId and logout requests.
+     *
+     * @param string $rebroadcastNodeUrl The rebroadcast node URL.
+     *
+     * @return void
+     */
+    public function addRebroadcastNode($rebroadcastNodeUrl)
+    {
+        // Store the rebroadcast node and set flag
+        $this->_rebroadcast = true;
+        $this->_rebroadcast_nodes[] = $rebroadcastNodeUrl;
+    }
+
+    /**
+     * An array to store extra rebroadcast curl options.
+     */
+    private $_rebroadcast_headers = array();
+
+    /**
+     * This method is used to add header parameters when rebroadcasting
+     * pgtIou/pgtId or logoutRequest.
+     *
+     * @param string $header Header to send when rebroadcasting.
+     *
+     * @return void
+     */
+    public function addRebroadcastHeader($header)
+    {
+        $this->_rebroadcast_headers[] = $header;
+    }
+
+    /**
+     * Constants used for determining rebroadcast type (logout or pgtIou/pgtId).
+     */
+    const LOGOUT = 0;
+    const PGTIOU = 1;
+
+    /**
+     * This method rebroadcasts logout/pgtIou requests. Can be LOGOUT,PGTIOU
+     *
+     * @param int $type type of rebroadcasting.
+     *
+     * @return void
+     */
+    private function _rebroadcast($type)
+    {
+        phpCAS::traceBegin();
+
+        $rebroadcast_curl_options = array(
+        CURLOPT_FAILONERROR => 1,
+        CURLOPT_FOLLOWLOCATION => 1,
+        CURLOPT_RETURNTRANSFER => 1,
+        CURLOPT_CONNECTTIMEOUT => 1,
+        CURLOPT_TIMEOUT => 4);
+
+        // Try to determine the IP address of the server
+        if (!empty($_SERVER['SERVER_ADDR'])) {
+            $ip = $_SERVER['SERVER_ADDR'];
+        } else if (!empty($_SERVER['LOCAL_ADDR'])) {
+            // IIS 7
+            $ip = $_SERVER['LOCAL_ADDR'];
+        }
+        // Try to determine the DNS name of the server
+        if (!empty($ip)) {
+            $dns = gethostbyaddr($ip);
+        }
+        $multiClassName = 'CAS_Request_CurlMultiRequest';
+        $multiRequest = new $multiClassName();
+
+        for ($i = 0; $i < sizeof($this->_rebroadcast_nodes); $i++) {
+            if ((($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::HOSTNAME) && !empty($dns) && (stripos($this->_rebroadcast_nodes[$i], $dns) === false)) || (($this->_getNodeType($this->_rebroadcast_nodes[$i]) == self::IP) && !empty($ip) && (stripos($this->_rebroadcast_nodes[$i], $ip) === false))) {
+                phpCAS::trace('Rebroadcast target URL: '.$this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI']);
+                $className = $this->_requestImplementation;
+                $request = new $className();
+
+                $url = $this->_rebroadcast_nodes[$i].$_SERVER['REQUEST_URI'];
+                $request->setUrl($url);
+
+                if (count($this->_rebroadcast_headers)) {
+                    $request->addHeaders($this->_rebroadcast_headers);
+                }
+
+                $request->makePost();
+                if ($type == self::LOGOUT) {
+                    // Logout request
+                    $request->setPostBody('rebroadcast=false&logoutRequest='.$_POST['logoutRequest']);
+                } else if ($type == self::PGTIOU) {
+                    // pgtIou/pgtId rebroadcast
+                    $request->setPostBody('rebroadcast=false');
+                }
+
+                $request->setCurlOptions($rebroadcast_curl_options);
+
+                $multiRequest->addRequest($request);
+            } else {
+                phpCAS::trace('Rebroadcast not sent to self: '.$this->_rebroadcast_nodes[$i].' == '.(!empty($ip)?$ip:'').'/'.(!empty($dns)?$dns:''));
+            }
+        }
+        // We need at least 1 request
+        if ($multiRequest->getNumRequests() > 0) {
+            $multiRequest->send();
+        }
+        phpCAS::traceEnd();
+    }
+
+    /** @} */
+}
+
+?>
diff --git a/CAS/CAS/CookieJar.php b/CAS/CAS/CookieJar.php
new file mode 100644 (file)
index 0000000..7f1f62f
--- /dev/null
@@ -0,0 +1,377 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/CookieJar.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class provides access to service cookies and handles parsing of response
+ * headers to pull out cookie values.
+ *
+ * @class    CAS_CookieJar
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_CookieJar
+{
+
+    private $_cookies;
+
+    /**
+     * Create a new cookie jar by passing it a reference to an array in which it
+     * should store cookies.
+     *
+     * @param array &$storageArray Array to store cookies
+     *
+     * @return void
+     */
+    public function __construct (array &$storageArray)
+    {
+        $this->_cookies =& $storageArray;
+    }
+
+    /**
+     * Store cookies for a web service request.
+     * Cookie storage is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $request_url      The URL that generated the response headers.
+     * @param array  $response_headers An array of the HTTP response header strings.
+     *
+     * @return void
+     *
+     * @access private
+     */
+    public function storeCookies ($request_url, $response_headers)
+    {
+        $urlParts = parse_url($request_url);
+        $defaultDomain = $urlParts['host'];
+
+        $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain);
+
+        // var_dump($cookies);
+        foreach ($cookies as $cookie) {
+            // Enforce the same-origin policy by verifying that the cookie
+            // would match the url that is setting it
+            if (!$this->cookieMatchesTarget($cookie, $urlParts)) {
+                continue;
+            }
+
+            // store the cookie
+            $this->storeCookie($cookie);
+
+            phpCAS::trace($cookie['name'].' -> '.$cookie['value']);
+        }
+    }
+
+    /**
+     * Retrieve cookies applicable for a web service request.
+     * Cookie applicability is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $request_url The url that the cookies will be for.
+     *
+     * @return array An array containing cookies. E.g. array('name' => 'val');
+     *
+     * @access private
+     */
+    public function getCookies ($request_url)
+    {
+        if (!count($this->_cookies)) {
+            return array();
+        }
+
+        // If our request URL can't be parsed, no cookies apply.
+        $target = parse_url($request_url);
+        if ($target === false) {
+            return array();
+        }
+
+        $this->expireCookies();
+
+        $matching_cookies = array();
+        foreach ($this->_cookies as $key => $cookie) {
+            if ($this->cookieMatchesTarget($cookie, $target)) {
+                $matching_cookies[$cookie['name']] = $cookie['value'];
+            }
+        }
+        return $matching_cookies;
+    }
+
+
+    /**
+     * Parse Cookies without PECL
+     * From the comments in http://php.net/manual/en/function.http-parse-cookie.php
+     *
+     * @param array  $header        array of header lines.
+     * @param string $defaultDomain The domain to use if none is specified in
+     * the cookie.
+     *
+     * @return array of cookies
+     */
+    protected function parseCookieHeaders( $header, $defaultDomain )
+    {
+        phpCAS::traceBegin();
+        $cookies = array();
+        foreach ( $header as $line ) {
+            if ( preg_match('/^Set-Cookie2?: /i', $line)) {
+                $cookies[] = $this->parseCookieHeader($line, $defaultDomain);
+            }
+        }
+
+        phpCAS::traceEnd($cookies);
+        return $cookies;
+    }
+
+    /**
+     * Parse a single cookie header line.
+     *
+     * Based on RFC2965 http://www.ietf.org/rfc/rfc2965.txt
+     *
+     * @param string $line          The header line.
+     * @param string $defaultDomain The domain to use if none is specified in
+     * the cookie.
+     *
+     * @return array
+     */
+    protected function parseCookieHeader ($line, $defaultDomain)
+    {
+        if (!$defaultDomain) {
+            throw new CAS_InvalidArgumentException('$defaultDomain was not provided.');
+        }
+
+        // Set our default values
+        $cookie = array(
+            'domain' => $defaultDomain,
+            'path' => '/',
+            'secure' => false,
+        );
+
+        $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));
+
+        // trim any trailing semicolons.
+        $line = trim($line, ';');
+
+        phpCAS::trace("Cookie Line: $line");
+
+        // This implementation makes the assumption that semicolons will not
+        // be present in quoted attribute values. While attribute values that
+        // contain semicolons are allowed by RFC2965, they are hopefully rare
+        // enough to ignore for our purposes. Most browsers make the same
+        // assumption.
+        $attributeStrings = explode(';', $line);
+
+        foreach ( $attributeStrings as $attributeString ) {
+            // split on the first equals sign and use the rest as value
+            $attributeParts = explode('=', $attributeString, 2);
+
+            $attributeName = trim($attributeParts[0]);
+            $attributeNameLC = strtolower($attributeName);
+
+            if (isset($attributeParts[1])) {
+                $attributeValue = trim($attributeParts[1]);
+                // Values may be quoted strings.
+                if (strpos($attributeValue, '"') === 0) {
+                    $attributeValue = trim($attributeValue, '"');
+                    // unescape any escaped quotes:
+                    $attributeValue = str_replace('\"', '"', $attributeValue);
+                }
+            } else {
+                $attributeValue = null;
+            }
+
+            switch ($attributeNameLC) {
+            case 'expires':
+                $cookie['expires'] = strtotime($attributeValue);
+                break;
+            case 'max-age':
+                $cookie['max-age'] = (int)$attributeValue;
+                // Set an expiry time based on the max-age
+                if ($cookie['max-age']) {
+                    $cookie['expires'] = time() + $cookie['max-age'];
+                } else {
+                    // If max-age is zero, then the cookie should be removed
+                    // imediately so set an expiry before now.
+                    $cookie['expires'] = time() - 1;
+                }
+                break;
+            case 'secure':
+                $cookie['secure'] = true;
+                break;
+            case 'domain':
+            case 'path':
+            case 'port':
+            case 'version':
+            case 'comment':
+            case 'commenturl':
+            case 'discard':
+            case 'httponly':
+                $cookie[$attributeNameLC] = $attributeValue;
+                break;
+            default:
+                $cookie['name'] = $attributeName;
+                $cookie['value'] = $attributeValue;
+            }
+        }
+
+        return $cookie;
+    }
+
+    /**
+     * Add, update, or remove a cookie.
+     *
+     * @param array $cookie A cookie array as created by parseCookieHeaders()
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function storeCookie ($cookie)
+    {
+        // Discard any old versions of this cookie.
+        $this->discardCookie($cookie);
+        $this->_cookies[] = $cookie;
+
+    }
+
+    /**
+     * Discard an existing cookie
+     *
+     * @param array $cookie An cookie
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function discardCookie ($cookie)
+    {
+        if (!isset($cookie['domain'])
+            || !isset($cookie['path'])
+            || !isset($cookie['path'])
+        ) {
+            throw new CAS_InvalidArgumentException('Invalid Cookie array passed.');
+        }
+
+        foreach ($this->_cookies as $key => $old_cookie) {
+            if ( $cookie['domain'] == $old_cookie['domain']
+                && $cookie['path'] == $old_cookie['path']
+                && $cookie['name'] == $old_cookie['name']
+            ) {
+                unset($this->_cookies[$key]);
+            }
+        }
+    }
+
+    /**
+     * Go through our stored cookies and remove any that are expired.
+     *
+     * @return void
+     *
+     * @access protected
+     */
+    protected function expireCookies ()
+    {
+        foreach ($this->_cookies as $key => $cookie) {
+            if (isset($cookie['expires']) && $cookie['expires'] < time()) {
+                unset($this->_cookies[$key]);
+            }
+        }
+    }
+
+    /**
+     * Answer true if cookie is applicable to a target.
+     *
+     * @param array $cookie An array of cookie attributes.
+     * @param array $target An array of URL attributes as generated by parse_url().
+     *
+     * @return bool
+     *
+     * @access private
+     */
+    protected function cookieMatchesTarget ($cookie, $target)
+    {
+        if (!is_array($target)) {
+            throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
+        }
+        if (!isset($target['host'])) {
+            throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
+        }
+
+        // Verify that the scheme matches
+        if ($cookie['secure'] && $target['scheme'] != 'https') {
+            return false;
+        }
+
+        // Verify that the host matches
+        // Match domain and mulit-host cookies
+        if (strpos($cookie['domain'], '.') === 0) {
+            // .host.domain.edu cookies are valid for host.domain.edu
+            if (substr($cookie['domain'], 1) == $target['host']) {
+                // continue with other checks
+            } else {
+                // non-exact host-name matches.
+                // check that the target host a.b.c.edu is within .b.c.edu
+                $pos = strripos($target['host'], $cookie['domain']);
+                if (!$pos) {
+                    return false;
+                }
+                // verify that the cookie domain is the last part of the host.
+                if ($pos + strlen($cookie['domain']) != strlen($target['host'])) {
+                    return false;
+                }
+                // verify that the host name does not contain interior dots as per
+                // RFC 2965 section 3.3.2  Rejecting Cookies
+                // http://www.ietf.org/rfc/rfc2965.txt
+                $hostname = substr($target['host'], 0, $pos);
+                if (strpos($hostname, '.') !== false) {
+                    return false;
+                }
+            }
+        } else {
+            // If the cookie host doesn't begin with '.', the host must case-insensitive
+            // match exactly
+            if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
+                return false;
+            }
+        }
+
+        // Verify that the port matches
+        if (isset($cookie['ports']) && !in_array($target['port'], $cookie['ports'])) {
+            return false;
+        }
+
+        // Verify that the path matches
+        if (strpos($target['path'], $cookie['path']) !== 0) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
+
+?>
diff --git a/CAS/CAS/Exception.php b/CAS/CAS/Exception.php
new file mode 100644 (file)
index 0000000..d956d19
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A root exception interface for all exceptions in phpCAS.
+ *
+ * All exceptions thrown in phpCAS should implement this interface to allow them
+ * to be caught as a category by clients. Each phpCAS exception should extend
+ * an appropriate SPL exception class that best fits its type.
+ *
+ * For example, an InvalidArgumentException in phpCAS should be defined as
+ *
+ *             class CAS_InvalidArgumentException
+ *                     extends InvalidArgumentException
+ *                     implements CAS_Exception
+ *             { }
+ *
+ * This definition allows the CAS_InvalidArgumentException to be caught as either
+ * an InvalidArgumentException or as a CAS_Exception.
+ *
+ * @class    CAS_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+interface CAS_Exception
+{
+
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/GracefullTerminationException.php b/CAS/CAS/GracefullTerminationException.php
new file mode 100644 (file)
index 0000000..6d845df
--- /dev/null
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/GracefullTerminationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An exception for terminatinating execution or to throw for unit testing
+ *
+ * @class     CAS_GracefullTerminationException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_GracefullTerminationException
+extends RuntimeException
+implements CAS_Exception
+{
+
+    /**
+     * Test if exceptions should be thrown or if we should just exit.
+     * In production usage we want to just exit cleanly when prompting the user
+     * for a redirect without filling the error logs with uncaught exceptions.
+     * In unit testing scenarios we cannot exit or we won't be able to continue
+     * with our tests.
+     *
+     * @param string $message Message Text
+     * @param string $code    Error code
+     *
+     * @return void
+     */
+    public function __construct ($message = 'Terminate Gracefully', $code = 0)
+    {
+        // Exit cleanly to avoid filling up the logs with uncaught exceptions.
+        if (self::$_exitWhenThrown) {
+            exit;
+        } else {
+            // Throw exceptions to allow unit testing to continue;
+            parent::__construct($message, $code);
+        }
+    }
+
+    private static $_exitWhenThrown = true;
+    /**
+    * Force phpcas to thow Exceptions instead of calling exit()
+    * Needed for unit testing. Generally shouldn't be used in production due to
+    * an increase in Apache error logging if CAS_GracefulTerminiationExceptions
+    * are not caught and handled.
+    *
+    * @return void
+    */
+    public static function throwInsteadOfExiting()
+    {
+        self::$_exitWhenThrown = false;
+    }
+
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/InvalidArgumentException.php b/CAS/CAS/InvalidArgumentException.php
new file mode 100644 (file)
index 0000000..ba43d39
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/InvalidArgumentException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Exception that denotes invalid arguments were passed.
+ *
+ * @class    CAS_InvalidArgumentException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_InvalidArgumentException
+extends InvalidArgumentException
+implements CAS_Exception
+{
+
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/Catalan.php b/CAS/CAS/Languages/Catalan.php
new file mode 100644 (file)
index 0000000..a0b64d8
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/Catalan.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Catalan language class
+ *
+ * @class    CAS_Languages_Catalan
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Catalan implements CAS_Languages_LanguageInterface
+{
+    /**
+    * Get the using server string
+    *
+    * @return string using server
+    */
+    public function getUsingServer()
+    {
+        return 'usant servidor';
+    }
+
+    /**
+    * Get authentication wanted string
+    *
+    * @return string authentication wanted
+    */
+    public function getAuthenticationWanted()
+    {
+        return 'Autentificació CAS necessària!';
+    }
+
+    /**
+    * Get logout string
+    *
+    * @return string logout
+    */
+    public function getLogout()
+    {
+        return 'Sortida de CAS necessària!';
+    }
+
+    /**
+    * Get the should have been redirected string
+    *
+    * @return string should habe been redirected
+    */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click <a href="%s">aquí</a> per a continuar.';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'Autentificació CAS fallida!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>No estàs autentificat.</p><p>Pots tornar a intentar-ho fent click <a href="%s">aquí</a>.</p><p>Si el problema persisteix hauría de contactar amb l\'<a href="mailto:%s">administrador d\'aquest llocc</a>.</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return 'El servei `<b>%s</b>\' no està disponible (<b>%s</b>).';
+    }
+}
diff --git a/CAS/CAS/Languages/English.php b/CAS/CAS/Languages/English.php
new file mode 100644 (file)
index 0000000..002c1ba
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/English.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * English language class
+ *
+ * @class    CAS_Languages_English
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_English implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'using server';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CAS Authentication wanted!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CAS logout wanted!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'You should already have been redirected to the CAS server. Click <a href="%s">here</a> to continue.';
+    }
+
+    /**
+    * Get authentication failed string
+    *
+    * @return string authentication failed
+    */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS Authentication failed!';
+    }
+
+    /**
+    * Get the your were not authenticated string
+    *
+    * @return string not authenticated
+    */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href="%s">here</a>.</p><p>If the problem persists, you may contact <a href="mailto:%s">the administrator of this site</a>.</p>';
+    }
+
+    /**
+    * Get the service unavailable string
+    *
+    * @return string service unavailable
+    */
+    public function getServiceUnavailable()
+    {
+        return 'The service `<b>%s</b>\' is not available (<b>%s</b>).';
+    }
+}
\ No newline at end of file
diff --git a/CAS/CAS/Languages/French.php b/CAS/CAS/Languages/French.php
new file mode 100644 (file)
index 0000000..b99847a
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/French.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * French language class
+ *
+ * @class    CAS_Languages_French
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_French implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'utilisant le serveur';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'Authentication CAS nécessaire&nbsp;!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Déconnexion demandée&nbsp;!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Vous auriez du etre redirigé(e) vers le serveur CAS. Cliquez <a href="%s">ici</a> pour continuer.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'Authentification CAS infructueuse&nbsp;!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Vous n\'avez pas été authentifié(e).</p><p>Vous pouvez soumettre votre requete à nouveau en cliquant <a href="%s">ici</a>.</p><p>Si le problème persiste, vous pouvez contacter <a href="mailto:%s">l\'administrateur de ce site</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Le service `<b>%s</b>\' est indisponible (<b>%s</b>)';
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/German.php b/CAS/CAS/Languages/German.php
new file mode 100644 (file)
index 0000000..84199d1
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/German.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Henrik Genssen <hg@mediafactory.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * German language class
+ *
+ * @class    CAS_Languages_German
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Henrik Genssen <hg@mediafactory.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_German implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'via Server';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CAS Authentifizierung erforderlich!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CAS Abmeldung!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'eigentlich h&auml;ten Sie zum CAS Server weitergeleitet werden sollen. Dr&uuml;cken Sie <a href="%s">hier</a> um fortzufahren.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS Anmeldung fehlgeschlagen!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontkatieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Der Dienst `<b>%s</b>\' ist nicht verf&uuml;gbar (<b>%s</b>).';
+    }
+}
+
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/Greek.php b/CAS/CAS/Languages/Greek.php
new file mode 100644 (file)
index 0000000..eb0f5ef
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/Greek.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Greek language class
+ *
+ * @class    CAS_Languages_Greek
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Vangelis Haniotakis <haniotak@ucnet.uoc.gr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Greek implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return '÷ñçóéìïðïéåßôáé ï åîõðçñåôçôÞò';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'Áðáéôåßôáé ç ôáõôïðïßçóç CAS!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'Áðáéôåßôáé ç áðïóýíäåóç áðü CAS!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Èá Ýðñåðå íá åß÷áôå áíáêáôåõèõíèåß óôïí åîõðçñåôçôÞ CAS. ÊÜíôå êëßê <a href="%s">åäþ</a> ãéá íá óõíå÷ßóåôå.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'Ç ôáõôïðïßçóç CAS áðÝôõ÷å!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>Äåí ôáõôïðïéçèÞêáôå.</p><p>Ìðïñåßôå íá îáíáðñïóðáèÞóåôå, êÜíïíôáò êëßê <a href="%s">åäþ</a>.</p><p>Åáí ôï ðñüâëçìá åðéìåßíåé, åëÜôå óå åðáöÞ ìå ôïí <a href="mailto:%s">äéá÷åéñéóôÞ</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'Ç õðçñåóßá `<b>%s</b>\' äåí åßíáé äéáèÝóéìç (<b>%s</b>).';
+    }
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/Japanese.php b/CAS/CAS/Languages/Japanese.php
new file mode 100644 (file)
index 0000000..e9cd121
--- /dev/null
@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/Japanese.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   fnorif <fnorif@yahoo.co.jp>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Japanese language class. Now Encoding is EUC-JP and LF
+ *
+ * @class    CAS_Languages_Japanese
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   fnorif <fnorif@yahoo.co.jp>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ **/
+class CAS_Languages_Japanese implements CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'using server';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return 'CAS�ˤ��ǧ�ڤ�Ԥ��ޤ�';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return 'CAS����?�����Ȥ��ޤ�!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'CAS�����Ф˹Ԥ�ɬ�פ�����ޤ�����ưŪ��ž������ʤ����� <a href="%s">������</a> �򥯥�å�����³�Ԥ��ޤ��';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return 'CAS�ˤ��ǧ�ڤ˼��Ԥ��ޤ���';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>ǧ�ڤǤ��ޤ���Ǥ���.</p><p>�⤦���٥ꥯ�����Ȥ������������<a href="%s">������</a>�򥯥�å�.</p><p>���꤬��褷�ʤ����� <a href="mailto:%s">���Υ����Ȥδ����</a>���䤤��碌�Ƥ�������.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return '�����ӥ� `<b>%s</b>\' �����ѤǤ��ޤ��� (<b>%s</b>).';
+    }
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/LanguageInterface.php b/CAS/CAS/Languages/LanguageInterface.php
new file mode 100644 (file)
index 0000000..5de93aa
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/LanguageInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Language Interface class for all internationalization files
+ *
+ * @class    CAS_Languages_LanguageInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+
+interface CAS_Languages_LanguageInterface
+{
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer();
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted();
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout();
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected();
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed();
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated();
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable();
+
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/Languages/Spanish.php b/CAS/CAS/Languages/Spanish.php
new file mode 100644 (file)
index 0000000..5675a41
--- /dev/null
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Language/Spanish.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Spanish language class
+ *
+ * @class    CAS_Languages_Spanish
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Iván-Benjamín García Torà <ivaniclixx@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+
+ * @sa @link internalLang Internationalization @endlink
+ * @ingroup internalLang
+ */
+class CAS_Languages_Spanish implements CAS_Languages_LanguageInterface
+{
+
+    /**
+     * Get the using server string
+     *
+     * @return string using server
+     */
+    public function getUsingServer()
+    {
+        return 'usando servidor';
+    }
+
+    /**
+     * Get authentication wanted string
+     *
+     * @return string authentication wanted
+     */
+    public function getAuthenticationWanted()
+    {
+        return '¡Autentificación CAS necesaria!';
+    }
+
+    /**
+     * Get logout string
+     *
+     * @return string logout
+     */
+    public function getLogout()
+    {
+        return '¡Salida CAS necesaria!';
+    }
+
+    /**
+     * Get the should have been redirected string
+     *
+     * @return string should habe been redirected
+     */
+    public function getShouldHaveBeenRedirected()
+    {
+        return 'Ya debería haber sido redireccionado al servidor CAS. Haga click <a href="%s">aquí</a> para continuar.';
+    }
+
+    /**
+     * Get authentication failed string
+     *
+     * @return string authentication failed
+     */
+    public function getAuthenticationFailed()
+    {
+        return '¡Autentificación CAS fallida!';
+    }
+
+    /**
+     * Get the your were not authenticated string
+     *
+     * @return string not authenticated
+     */
+    public function getYouWereNotAuthenticated()
+    {
+        return '<p>No estás autentificado.</p><p>Puedes volver a intentarlo haciendo click <a href="%s">aquí</a>.</p><p>Si el problema persiste debería contactar con el <a href="mailto:%s">administrador de este sitio</a>.</p>';
+    }
+
+    /**
+     * Get the service unavailable string
+     *
+     * @return string service unavailable
+     */
+    public function getServiceUnavailable()
+    {
+        return 'El servicio `<b>%s</b>\' no está disponible (<b>%s</b>).';
+    }
+}
+?>
diff --git a/CAS/CAS/OutOfSequenceException.php b/CAS/CAS/OutOfSequenceException.php
new file mode 100644 (file)
index 0000000..d101811
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/OutOfSequenceException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class defines Exceptions that should be thrown when the sequence of
+ * operations is invalid. Examples are:
+ *             - Requesting the response before executing a request.
+ *             - Changing the URL of a request after executing the request.
+ *
+ * @class    CAS_OutOfSequenceException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_OutOfSequenceException
+extends BadMethodCallException
+implements CAS_Exception
+{
+
+}
diff --git a/CAS/CAS/PGTStorage/AbstractStorage.php b/CAS/CAS/PGTStorage/AbstractStorage.php
new file mode 100644 (file)
index 0000000..6c964f5
--- /dev/null
@@ -0,0 +1,220 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/PGTStorage/AbstractStorage.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Basic class for PGT storage
+ * The CAS_PGTStorage_AbstractStorage class is a generic class for PGT storage.
+ * This class should not be instanciated itself but inherited by specific PGT
+ * storage classes.
+ *
+ * @class CAS_PGTStorage_AbstractStorage
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @ingroup internalPGTStorage
+ */
+
+abstract class CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalPGTStorage
+     * @{
+     */
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The constructor of the class, should be called only by inherited classes.
+     *
+     * @param CAS_Client $cas_parent the CAS _client instance that creates the
+     * current object.
+     *
+     * @return void
+     *
+     * @protected
+     */
+    function __construct($cas_parent)
+    {
+        phpCAS::traceBegin();
+        if ( !$cas_parent->isProxy() ) {
+            phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy');
+        }
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This virtual method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return void
+     *
+     * @public
+     */
+    function getStorageType()
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /**
+     * This virtual method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return void
+     *
+     * @public
+     */
+    function getStorageInfo()
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    // ########################################################################
+    //  ERROR HANDLING
+    // ########################################################################
+
+    /**
+     * string used to store an error message. Written by
+     * PGTStorage::setErrorMessage(), read by PGTStorage::getErrorMessage().
+     *
+     * @hideinitializer
+     * @deprecated not used.
+     */
+    var $_error_message=false;
+
+    /**
+     * This method sets en error message, which can be read later by
+     * PGTStorage::getErrorMessage().
+     *
+     * @param string $error_message an error message
+     *
+     * @return void
+     *
+     * @deprecated not used.
+     */
+    function setErrorMessage($error_message)
+    {
+        $this->_error_message = $error_message;
+    }
+
+    /**
+     * This method returns an error message set by PGTStorage::setErrorMessage().
+     *
+     * @return an error message when set by PGTStorage::setErrorMessage(), FALSE
+     * otherwise.
+     *
+     * @deprecated not used.
+     */
+    function getErrorMessage()
+    {
+        return $this->_error_message;
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * a boolean telling if the storage has already been initialized. Written by
+     * PGTStorage::init(), read by PGTStorage::isInitialized().
+     *
+     * @hideinitializer
+     */
+    var $_initialized = false;
+
+    /**
+     * This method tells if the storage has already been intialized.
+     *
+     * @return a boolean
+     *
+     * @protected
+     */
+    function isInitialized()
+    {
+        return $this->_initialized;
+    }
+
+    /**
+     * This virtual method initializes the object.
+     *
+     * @return void
+     */
+    function init()
+    {
+        $this->_initialized = true;
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This virtual method stores a PGT and its corresponding PGT Iuo.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     *
+     * @note Should never be called.
+     *
+     */
+    function write($pgt,$pgt_iou)
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /**
+     * This virtual method reads a PGT corresponding to a PGT Iou and deletes
+     * the corresponding storage entry.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     *
+     * @note Should never be called.
+     */
+    function read($pgt_iou)
+    {
+        phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called');
+    }
+
+    /** @} */
+
+}
+
+?>
diff --git a/CAS/CAS/PGTStorage/Db.php b/CAS/CAS/PGTStorage/Db.php
new file mode 100644 (file)
index 0000000..1f635f8
--- /dev/null
@@ -0,0 +1,429 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/PGTStorage/Db.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Daniel Frett <daniel.frett@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+define('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts');
+
+/**
+ * Basic class for PGT database storage
+ * The CAS_PGTStorage_Db class is a class for PGT database storage.
+ *
+ * @class    CAS_PGTStorage_Db
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Daniel Frett <daniel.frett@gmail.com>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ * @ingroup internalPGTStorageDb
+ */
+
+class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalCAS_PGTStorageDb
+     * @{
+     */
+
+    /**
+     * the PDO object to use for database interactions
+     */
+    private $_pdo;
+
+    /**
+     * This method returns the PDO object to use for database interactions.
+     *
+     * @return the PDO object
+     */
+    private function _getPdo()
+    {
+        return $this->_pdo;
+    }
+
+    /**
+     * database connection options to use when creating a new PDO object
+     */
+    private $_dsn;
+    private $_username;
+    private $_password;
+    private $_table_options;
+
+    /**
+     * the table to use for storing/retrieving pgt's
+     */
+    private $_table;
+
+    /**
+     * This method returns the table to use when storing/retrieving PGT's
+     *
+     * @return the name of the pgt storage table.
+     */
+    private function _getTable()
+    {
+        return $this->_table;
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return an informational string.
+     */
+    public function getStorageType()
+    {
+        return "db";
+    }
+
+    /**
+     * This method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return an informational string.
+     * @public
+     */
+    public function getStorageInfo()
+    {
+        return 'table=`'.$this->_getTable().'\'';
+    }
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The class constructor.
+     *
+     * @param CAS_Client $cas_parent     the CAS_Client instance that creates
+     * the object.
+     * @param string     $dsn_or_pdo     a dsn string to use for creating a PDO
+     * object or a PDO object
+     * @param string     $username       the username to use when connecting to
+     * the database
+     * @param string     $password       the password to use when connecting to
+     * the database
+     * @param string     $table          the table to use for storing and
+     * retrieving PGT's
+     * @param string     $driver_options any driver options to use when
+     * connecting to the database
+     */
+    public function __construct($cas_parent, $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
+    {
+        phpCAS::traceBegin();
+        // call the ancestor's constructor
+        parent::__construct($cas_parent);
+
+        // set default values
+        if ( empty($table) ) {
+            $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE;
+        }
+        if ( !is_array($driver_options) ) {
+            $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION);
+        }
+
+        // store the specified parameters
+        if ($dsn_or_pdo instanceof PDO) {
+            $this->_pdo = $dsn_or_pdo;
+        } else {
+            $this->_dsn = $dsn_or_pdo;
+            $this->_username = $username;
+            $this->_password = $password;
+            $this->_driver_options = $driver_options;
+        }
+
+        // store the table name
+        $this->_table = $table;
+
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * This method is used to initialize the storage. Halts on error.
+     *
+     * @return void
+     */
+    public function init()
+    {
+        phpCAS::traceBegin();
+        // if the storage has already been initialized, return immediatly
+        if ($this->isInitialized()) {
+            return;
+        }
+
+        // initialize the base object
+        parent::init();
+
+        // create the PDO object if it doesn't exist already
+        if (!($this->_pdo instanceof PDO)) {
+            try {
+                $this->_pdo = new PDO($this->_dsn, $this->_username, $this->_password, $this->_driver_options);
+            }
+            catch(PDOException $e) {
+                phpCAS::error('Database connection error: ' . $e->getMessage());
+            }
+        }
+
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  PDO database interaction
+    // ########################################################################
+
+    /**
+     * attribute that stores the previous error mode for the PDO handle while
+     * processing a transaction
+     */
+    private $_errMode;
+
+    /**
+     * This method will enable the Exception error mode on the PDO object
+     *
+     * @return void
+     */
+    private function _setErrorMode()
+    {
+        // get PDO object and enable exception error mode
+        $pdo = $this->_getPdo();
+        $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE);
+        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+    }
+
+    /**
+     * this method will reset the error mode on the PDO object
+     *
+     * @return void
+     */
+    private function _resetErrorMode()
+    {
+        // get PDO object and reset the error mode to what it was originally
+        $pdo = $this->_getPdo();
+        $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode);
+    }
+
+    // ########################################################################
+    //  database queries
+    // ########################################################################
+    // these queries are potentially unsafe because the person using this library
+    // can set the table to use, but there is no reliable way to escape SQL
+    // fieldnames in PDO yet
+
+    /**
+     * This method returns the query used to create a pgt storage table
+     *
+     * @return the create table SQL, no bind params in query
+     */
+    protected function createTableSql()
+    {
+        return 'CREATE TABLE ' . $this->_getTable() . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
+    }
+
+    /**
+     * This method returns the query used to store a pgt
+     *
+     * @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained in the query
+     */
+    protected function storePgtSql()
+    {
+        return 'INSERT INTO ' . $this->_getTable() . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
+    }
+
+    /**
+     * This method returns the query used to retrieve a pgt. the first column of the first row should contain the pgt
+     *
+     * @return the retrieve PGT SQL, :pgt_iou is the only bind param contained in the query
+     */
+    protected function retrievePgtSql()
+    {
+        return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';
+    }
+
+    /**
+     * This method returns the query used to delete a pgt.
+     *
+     * @return the delete PGT SQL, :pgt_iou is the only bind param contained in the query
+     */
+    protected function deletePgtSql()
+    {
+        return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou';
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This method creates the database table used to store pgt's and pgtiou's
+     *
+     * @return void
+     */
+    public function createTable()
+    {
+        phpCAS::traceBegin();
+
+        // initialize this PGTStorage object if it hasn't been initialized yet
+        if ( !$this->isInitialized() ) {
+            $this->init();
+        }
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            $query = $pdo->query($this->createTableSQL());
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::error('error creating PGT storage table: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method stores a PGT and its corresponding PGT Iou in the database.
+     * Echoes a warning on error.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     */
+    public function write($pgt, $pgt_iou)
+    {
+        phpCAS::traceBegin();
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            $query = $pdo->prepare($this->storePgtSql());
+            $query->bindValue(':pgt', $pgt, PDO::PARAM_STR);
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::error('error writing PGT to database: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method reads a PGT corresponding to a PGT Iou and deletes the
+     * corresponding db entry.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return the corresponding PGT, or FALSE on error
+     */
+    public function read($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $pgt = false;
+
+        // initialize the PDO object for this method
+        $pdo = $this->_getPdo();
+        $this->_setErrorMode();
+
+        try {
+            $pdo->beginTransaction();
+
+            // fetch the pgt for the specified pgt_iou
+            $query = $pdo->prepare($this->retrievePgtSql());
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $pgt = $query->fetchColumn(0);
+            $query->closeCursor();
+
+            // delete the specified pgt_iou from the database
+            $query = $pdo->prepare($this->deletePgtSql());
+            $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR);
+            $query->execute();
+            $query->closeCursor();
+
+            $pdo->commit();
+        }
+        catch(PDOException $e) {
+            // attempt rolling back the transaction before throwing a phpCAS error
+            try {
+                $pdo->rollBack();
+            }
+            catch(PDOException $e) {
+            }
+            phpCAS::trace('error reading PGT from database: ' . $e->getMessage());
+        }
+
+        // reset the PDO object
+        $this->_resetErrorMode();
+
+        phpCAS::traceEnd();
+        return $pgt;
+    }
+
+    /** @} */
+
+}
+
+?>
diff --git a/CAS/CAS/PGTStorage/File.php b/CAS/CAS/PGTStorage/File.php
new file mode 100644 (file)
index 0000000..80a1ea1
--- /dev/null
@@ -0,0 +1,259 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/PGTStorage/AbstractStorage.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * The CAS_PGTStorage_File class is a class for PGT file storage. An instance of
+ * this class is returned by CAS_Client::SetPGTStorageFile().
+ *
+ * @class    CAS_PGTStorage_File
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Pascal Aubry <pascal.aubry@univ-rennes1.fr>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ *
+ * @ingroup internalPGTStorageFile
+ */
+
+class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage
+{
+    /**
+     * @addtogroup internalPGTStorageFile
+     * @{
+     */
+
+    /**
+     * a string telling where PGT's should be stored on the filesystem. Written by
+     * PGTStorageFile::PGTStorageFile(), read by getPath().
+     *
+     * @private
+     */
+    var $_path;
+
+    /**
+     * This method returns the name of the directory where PGT's should be stored
+     * on the filesystem.
+     *
+     * @return the name of a directory (with leading and trailing '/')
+     *
+     * @private
+     */
+    function getPath()
+    {
+        return $this->_path;
+    }
+
+    // ########################################################################
+    //  DEBUGGING
+    // ########################################################################
+
+    /**
+     * This method returns an informational string giving the type of storage
+     * used by the object (used for debugging purposes).
+     *
+     * @return an informational string.
+     * @public
+     */
+    function getStorageType()
+    {
+        return "file";
+    }
+
+    /**
+     * This method returns an informational string giving informations on the
+     * parameters of the storage.(used for debugging purposes).
+     *
+     * @return an informational string.
+     * @public
+     */
+    function getStorageInfo()
+    {
+        return 'path=`'.$this->getPath().'\'';
+    }
+
+    // ########################################################################
+    //  CONSTRUCTOR
+    // ########################################################################
+
+    /**
+     * The class constructor, called by CAS_Client::SetPGTStorageFile().
+     *
+     * @param CAS_Client $cas_parent the CAS_Client instance that creates the object.
+     * @param string     $path       the path where the PGT's should be stored
+     *
+     * @return void
+     *
+     * @public
+     */
+    function __construct($cas_parent,$path)
+    {
+        phpCAS::traceBegin();
+        // call the ancestor's constructor
+        parent::__construct($cas_parent);
+
+        if (empty($path)) {
+            $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;
+        }
+        // check that the path is an absolute path
+        if (getenv("OS")=="Windows_NT") {
+
+            if (!preg_match('`^[a-zA-Z]:`', $path)) {
+                phpCAS::error('an absolute path is needed for PGT storage to file');
+            }
+
+        } else {
+
+            if ( $path[0] != '/' ) {
+                phpCAS::error('an absolute path is needed for PGT storage to file');
+            }
+
+            // store the path (with a leading and trailing '/')
+            $path = preg_replace('|[/]*$|', '/', $path);
+            $path = preg_replace('|^[/]*|', '/', $path);
+        }
+
+        $this->_path = $path;
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  INITIALIZATION
+    // ########################################################################
+
+    /**
+     * This method is used to initialize the storage. Halts on error.
+     *
+     * @return void
+     * @public
+     */
+    function init()
+    {
+        phpCAS::traceBegin();
+        // if the storage has already been initialized, return immediatly
+        if ($this->isInitialized()) {
+            return;
+        }
+        // call the ancestor's method (mark as initialized)
+        parent::init();
+        phpCAS::traceEnd();
+    }
+
+    // ########################################################################
+    //  PGT I/O
+    // ########################################################################
+
+    /**
+     * This method returns the filename corresponding to a PGT Iou.
+     *
+     * @param string $pgt_iou the PGT iou.
+     *
+     * @return a filename
+     * @private
+     */
+    function getPGTIouFilename($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $filename = $this->getPath().$pgt_iou.'.plain';
+        phpCAS::traceEnd($filename);
+        return $filename;
+    }
+
+    /**
+     * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a
+     * warning on error.
+     *
+     * @param string $pgt     the PGT
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return void
+     *
+     * @public
+     */
+    function write($pgt,$pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $fname = $this->getPGTIouFilename($pgt_iou);
+        if (!file_exists($fname)) {
+            touch($fname);
+            // Chmod will fail on windows
+            @chmod($fname, 0600);
+            if ($f=fopen($fname, "w")) {
+                if (fputs($f, $pgt) === false) {
+                    phpCAS::error('could not write PGT to `'.$fname.'\'');
+                }
+                phpCAS::trace('Successful write of PGT to `'.$fname.'\'');
+                fclose($f);
+            } else {
+                phpCAS::error('could not open `'.$fname.'\'');
+            }
+        } else {
+            phpCAS::error('File exists: `'.$fname.'\'');
+        }
+        phpCAS::traceEnd();
+    }
+
+    /**
+     * This method reads a PGT corresponding to a PGT Iou and deletes the
+     * corresponding file.
+     *
+     * @param string $pgt_iou the PGT iou
+     *
+     * @return the corresponding PGT, or FALSE on error
+     *
+     * @public
+     */
+    function read($pgt_iou)
+    {
+        phpCAS::traceBegin();
+        $pgt = false;
+        $fname = $this->getPGTIouFilename($pgt_iou);
+        if (file_exists($fname)) {
+            if (!($f=fopen($fname, "r"))) {
+                phpCAS::error('could not open `'.$fname.'\'');
+            } else {
+                if (($pgt=fgets($f)) === false) {
+                    phpCAS::error('could not read PGT from `'.$fname.'\'');
+                }
+                phpCAS::trace('Successful read of PGT to `'.$fname.'\'');
+                fclose($f);
+            }
+            // delete the PGT file
+            @unlink($fname);
+        } else {
+            phpCAS::error('No such file `'.$fname.'\'');
+        }
+        phpCAS::traceEnd($pgt);
+        return $pgt;
+    }
+
+    /** @} */
+
+}
+?>
\ No newline at end of file
diff --git a/CAS/CAS/PGTStorage/pgt-file.php b/CAS/CAS/PGTStorage/pgt-file.php
deleted file mode 100644 (file)
index e4190a8..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-<?php\r
-/*\r
- * Copyright © 2003-2010, The ESUP-Portail consortium & the JA-SIG Collaborative.\r
- * All rights reserved.\r
- * \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are met:\r
- * \r
- *     * Redistributions of source code must retain the above copyright notice,\r
- *       this list of conditions and the following disclaimer.\r
- *     * Redistributions in binary form must reproduce the above copyright notice,\r
- *       this list of conditions and the following disclaimer in the documentation\r
- *       and/or other materials provided with the distribution.\r
- *     * Neither the name of the ESUP-Portail consortium & the JA-SIG\r
- *       Collaborative nor the names of its contributors may be used to endorse or\r
- *       promote products derived from this software without specific prior\r
- *       written permission.\r
-\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- */\r
-/**\r
- * @file CAS/PGTStorage/pgt-file.php\r
- * Basic class for PGT file storage\r
- */\r
-\r
-/**\r
- * @class PGTStorageFile\r
- * The PGTStorageFile class is a class for PGT file storage. An instance of \r
- * this class is returned by CASClient::SetPGTStorageFile().\r
- *\r
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- *\r
- * @ingroup internalPGTStorageFile\r
- */\r
-\r
-class PGTStorageFile extends PGTStorage\r
-{\r
-  /** \r
-   * @addtogroup internalPGTStorageFile \r
-   * @{ \r
-   */\r
-\r
-  /**\r
-   * a string telling where PGT's should be stored on the filesystem. Written by\r
-   * PGTStorageFile::PGTStorageFile(), read by getPath().\r
-   *\r
-   * @private\r
-   */\r
-  var $_path;\r
-\r
-  /**\r
-   * This method returns the name of the directory where PGT's should be stored \r
-   * on the filesystem.\r
-   *\r
-   * @return the name of a directory (with leading and trailing '/')\r
-   *\r
-   * @private\r
-   */\r
-  function getPath()\r
-    {\r
-      return $this->_path;\r
-    }\r
-\r
-  /**\r
-   * a string telling the format to use to store PGT's (plain or xml). Written by\r
-   * PGTStorageFile::PGTStorageFile(), read by getFormat().\r
-   *\r
-   * @private\r
-   */\r
-  var $_format;\r
-\r
-  /**\r
-   * This method returns the format to use when storing PGT's on the filesystem.\r
-   *\r
-   * @return a string corresponding to the format used (plain or xml).\r
-   *\r
-   * @private\r
-   */\r
-  function getFormat()\r
-    {\r
-      return $this->_format;\r
-    }\r
-\r
-  // ########################################################################\r
-  //  DEBUGGING\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * This method returns an informational string giving the type of storage\r
-   * used by the object (used for debugging purposes).\r
-   *\r
-   * @return an informational string.\r
-   * @public\r
-   */\r
-  function getStorageType()\r
-    {\r
-      return "file";\r
-    }\r
-\r
-  /**\r
-   * This method returns an informational string giving informations on the\r
-   * parameters of the storage.(used for debugging purposes).\r
-   *\r
-   * @return an informational string.\r
-   * @public\r
-   */\r
-  function getStorageInfo()\r
-    {\r
-      return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\'';\r
-    }\r
-\r
-  // ########################################################################\r
-  //  CONSTRUCTOR\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * The class constructor, called by CASClient::SetPGTStorageFile().\r
-   *\r
-   * @param $cas_parent the CASClient instance that creates the object.\r
-   * @param $format the format used to store the PGT's (`plain' and `xml' allowed).\r
-   * @param $path the path where the PGT's should be stored\r
-   *\r
-   * @public\r
-   */\r
-  function PGTStorageFile($cas_parent,$format,$path)\r
-    {\r
-      phpCAS::traceBegin();\r
-      // call the ancestor's constructor\r
-      $this->PGTStorage($cas_parent);\r
-\r
-      if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT;\r
-      if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH;\r
-\r
-      // check that the path is an absolute path\r
-      if (getenv("OS")=="Windows_NT"){\r
-       \r
-        if (!preg_match('`^[a-zA-Z]:`', $path)) {\r
-               phpCAS::error('an absolute path is needed for PGT storage to file');\r
-       }\r
-       \r
-      }\r
-      else\r
-      {\r
-      \r
-       if ( $path[0] != '/' ) {\r
-                       phpCAS::error('an absolute path is needed for PGT storage to file');\r
-       }\r
-\r
-       // store the path (with a leading and trailing '/')      \r
-       $path = preg_replace('|[/]*$|','/',$path);\r
-       $path = preg_replace('|^[/]*|','/',$path);\r
-      }\r
-      \r
-      $this->_path = $path;\r
-      // check the format and store it\r
-      switch ($format) {\r
-      case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN:\r
-      case CAS_PGT_STORAGE_FILE_FORMAT_XML:\r
-       $this->_format = $format;\r
-       break;\r
-      default:\r
-       phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)');\r
-      }\r
-      phpCAS::traceEnd();      \r
-    }\r
-\r
-  // ########################################################################\r
-  //  INITIALIZATION\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * This method is used to initialize the storage. Halts on error.\r
-   *\r
-   * @public\r
-   */\r
-  function init()\r
-    {\r
-      phpCAS::traceBegin();\r
-      // if the storage has already been initialized, return immediatly\r
-      if ( $this->isInitialized() )\r
-       return;\r
-      // call the ancestor's method (mark as initialized)\r
-      parent::init();\r
-      phpCAS::traceEnd();      \r
-    }\r
-\r
-  // ########################################################################\r
-  //  PGT I/O\r
-  // ########################################################################\r
-\r
-  /**\r
-   * This method returns the filename corresponding to a PGT Iou.\r
-   *\r
-   * @param $pgt_iou the PGT iou.\r
-   *\r
-   * @return a filename\r
-   * @private\r
-   */\r
-  function getPGTIouFilename($pgt_iou)\r
-    {\r
-      phpCAS::traceBegin();\r
-      $filename = $this->getPath().$pgt_iou.'.'.$this->getFormat();\r
-      phpCAS::traceEnd($filename);\r
-      return $filename;\r
-    }\r
-  \r
-  /**\r
-   * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a\r
-   * warning on error.\r
-   *\r
-   * @param $pgt the PGT\r
-   * @param $pgt_iou the PGT iou\r
-   *\r
-   * @public\r
-   */\r
-  function write($pgt,$pgt_iou)\r
-         {\r
-         phpCAS::traceBegin();\r
-         $fname = $this->getPGTIouFilename($pgt_iou);\r
-         if(!file_exists($fname)){\r
-                 if ( $f=fopen($fname,"w") ) {\r
-                         if ( fputs($f,$pgt) === FALSE ) {\r
-                                 phpCAS::error('could not write PGT to `'.$fname.'\'');\r
-                         }\r
-                         fclose($f);\r
-                 } else {\r
-                         phpCAS::error('could not open `'.$fname.'\'');\r
-                 }\r
-         }else{\r
-                 phpCAS::error('File exists: `'.$fname.'\'');\r
-         }\r
-         phpCAS::traceEnd();      \r
-         }\r
-\r
-  /**\r
-   * This method reads a PGT corresponding to a PGT Iou and deletes the \r
-   * corresponding file.\r
-   *\r
-   * @param $pgt_iou the PGT iou\r
-   *\r
-   * @return the corresponding PGT, or FALSE on error\r
-   *\r
-   * @public\r
-   */\r
-  function read($pgt_iou)\r
-         {\r
-         phpCAS::traceBegin();\r
-         $pgt = FALSE;\r
-         $fname = $this->getPGTIouFilename($pgt_iou);\r
-         if (file_exists($fname)){\r
-                 if ( !($f=fopen($fname,"r")) ) {\r
-                         phpCAS::trace('could not open `'.$fname.'\'');\r
-                 } else {\r
-                         if ( ($pgt=fgets($f)) === FALSE ) {\r
-                                 phpCAS::trace('could not read PGT from `'.$fname.'\'');\r
-                         } \r
-                         fclose($f);\r
-                 }\r
-                 \r
-                 // delete the PGT file\r
-                 @unlink($fname);\r
-         }else{\r
-                 phpCAS::trace('No such file `'.$fname.'\'');\r
-         }\r
-         phpCAS::traceEnd($pgt);\r
-         return $pgt;\r
-         }\r
-  \r
-  /** @} */\r
-  \r
-}\r
-\r
-  \r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/PGTStorage/pgt-main.php b/CAS/CAS/PGTStorage/pgt-main.php
deleted file mode 100644 (file)
index aaf377f..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-<?php\r
-/*\r
- * Copyright © 2003-2010, The ESUP-Portail consortium & the JA-SIG Collaborative.\r
- * All rights reserved.\r
- * \r
- * Redistribution and use in source and binary forms, with or without\r
- * modification, are permitted provided that the following conditions are met:\r
- * \r
- *     * Redistributions of source code must retain the above copyright notice,\r
- *       this list of conditions and the following disclaimer.\r
- *     * Redistributions in binary form must reproduce the above copyright notice,\r
- *       this list of conditions and the following disclaimer in the documentation\r
- *       and/or other materials provided with the distribution.\r
- *     * Neither the name of the ESUP-Portail consortium & the JA-SIG\r
- *       Collaborative nor the names of its contributors may be used to endorse or\r
- *       promote products derived from this software without specific prior\r
- *       written permission.\r
-\r
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\r
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\r
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- */\r
-/**\r
- * @file CAS/PGTStorage/pgt-main.php\r
- * Basic class for PGT storage\r
- */\r
-\r
-/**\r
- * @class PGTStorage\r
- * The PGTStorage class is a generic class for PGT storage. This class should\r
- * not be instanciated itself but inherited by specific PGT storage classes.\r
- *\r
- * @author   Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- *\r
- * @ingroup internalPGTStorage\r
- */\r
-\r
-class PGTStorage\r
-{\r
-  /** \r
-   * @addtogroup internalPGTStorage\r
-   * @{ \r
-   */\r
-\r
-  // ########################################################################\r
-  //  CONSTRUCTOR\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * The constructor of the class, should be called only by inherited classes.\r
-   *\r
-   * @param $cas_parent the CASclient instance that creates the current object.\r
-   *\r
-   * @protected\r
-   */\r
-  function PGTStorage($cas_parent)\r
-    {\r
-      phpCAS::traceBegin();\r
-      if ( !$cas_parent->isProxy() ) {\r
-       phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy'); \r
-      }\r
-      phpCAS::traceEnd();\r
-    }\r
-\r
-  // ########################################################################\r
-  //  DEBUGGING\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * This virtual method returns an informational string giving the type of storage\r
-   * used by the object (used for debugging purposes).\r
-   *\r
-   * @public\r
-   */\r
-  function getStorageType()\r
-    {\r
-      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); \r
-    }\r
-\r
-  /**\r
-   * This virtual method returns an informational string giving informations on the\r
-   * parameters of the storage.(used for debugging purposes).\r
-   *\r
-   * @public\r
-   */\r
-  function getStorageInfo()\r
-    {\r
-      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); \r
-    }\r
-\r
-  // ########################################################################\r
-  //  ERROR HANDLING\r
-  // ########################################################################\r
-  \r
-  /**\r
-   * string used to store an error message. Written by PGTStorage::setErrorMessage(),\r
-   * read by PGTStorage::getErrorMessage().\r
-   *\r
-   * @hideinitializer\r
-   * @private\r
-   * @deprecated not used.\r
-   */\r
-  var $_error_message=FALSE;\r
-\r
-  /**\r
-   * This method sets en error message, which can be read later by \r
-   * PGTStorage::getErrorMessage().\r
-   *\r
-   * @param $error_message an error message\r
-   *\r
-   * @protected\r
-   * @deprecated not used.\r
-   */\r
-  function setErrorMessage($error_message)\r
-    {\r
-      $this->_error_message = $error_message;\r
-    }\r
-\r
-  /**\r
-   * This method returns an error message set by PGTStorage::setErrorMessage().\r
-   *\r
-   * @return an error message when set by PGTStorage::setErrorMessage(), FALSE\r
-   * otherwise.\r
-   *\r
-   * @public\r
-   * @deprecated not used.\r
-   */\r
-  function getErrorMessage()\r
-    {\r
-      return $this->_error_message;\r
-    }\r
-\r
-  // ########################################################################\r
-  //  INITIALIZATION\r
-  // ########################################################################\r
-\r
-  /**\r
-   * a boolean telling if the storage has already been initialized. Written by \r
-   * PGTStorage::init(), read by PGTStorage::isInitialized().\r
-   *\r
-   * @hideinitializer\r
-   * @private\r
-   */\r
-  var $_initialized = FALSE;\r
-\r
-  /**\r
-   * This method tells if the storage has already been intialized.\r
-   *\r
-   * @return a boolean\r
-   *\r
-   * @protected\r
-   */\r
-  function isInitialized()\r
-    {\r
-      return $this->_initialized;\r
-    }\r
-\r
-  /**\r
-   * This virtual method initializes the object.\r
-   *\r
-   * @protected\r
-   */\r
-  function init()\r
-    {\r
-      $this->_initialized = TRUE;\r
-    }\r
-\r
-  // ########################################################################\r
-  //  PGT I/O\r
-  // ########################################################################\r
-\r
-  /**\r
-   * This virtual method stores a PGT and its corresponding PGT Iuo.\r
-   * @note Should never be called.\r
-   *\r
-   * @param $pgt the PGT\r
-   * @param $pgt_iou the PGT iou\r
-   *\r
-   * @protected\r
-   */\r
-  function write($pgt,$pgt_iou)\r
-    {\r
-      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); \r
-    }\r
-\r
-  /**\r
-   * This virtual method reads a PGT corresponding to a PGT Iou and deletes\r
-   * the corresponding storage entry.\r
-   * @note Should never be called.\r
-   *\r
-   * @param $pgt_iou the PGT iou\r
-   *\r
-   * @protected\r
-   */\r
-  function read($pgt_iou)\r
-    {\r
-      phpCAS::error(__CLASS__.'::'.__FUNCTION__.'() should never be called'); \r
-    }\r
-\r
-  /** @} */\r
-  \r
-} \r
-\r
-// include specific PGT storage classes\r
-include_once(dirname(__FILE__).'/pgt-file.php'); \r
-  \r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/ProxiedService.php b/CAS/CAS/ProxiedService.php
new file mode 100644 (file)
index 0000000..d70ca9c
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to interact with phpCAS.
+ *
+ * Proxy service handlers must implement this interface as well as call
+ * phpCAS::initializeProxiedService($this) at some point in their implementation.
+ *
+ * While not required, proxy-authenticated service handlers are encouraged to
+ * implement the CAS_ProxiedService_Testable interface to facilitate unit testing.
+ *
+ * @class    CAS_ProxiedService
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService
+{
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl ();
+
+    /**
+     * Register a proxy ticket with the ProxiedService that it can use when
+     * making requests.
+     *
+     * @param string $proxyTicket Proxy ticket string
+     *
+     * @return void
+     * @throws InvalidArgumentException If the $proxyTicket is invalid.
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized/set.
+     */
+    public function setProxyTicket ($proxyTicket);
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Abstract.php b/CAS/CAS/ProxiedService/Abstract.php
new file mode 100644 (file)
index 0000000..d8d5338
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Abstract.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class implements common methods for ProxiedService implementations included
+ * with phpCAS.
+ *
+ * @class    CAS_ProxiedService_Abstract
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_ProxiedService_Abstract
+implements CAS_ProxiedService, CAS_ProxiedService_Testable
+{
+
+    /**
+     * The proxy ticket that can be used when making service requests.
+     * @var string $_proxyTicket;
+     */
+    private $_proxyTicket;
+
+    /**
+     * Register a proxy ticket with the Proxy that it can use when making requests.
+     *
+     * @param string $proxyTicket proxy ticket
+     *
+     * @return void
+     * @throws InvalidArgumentException If the $proxyTicket is invalid.
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
+     */
+    public function setProxyTicket ($proxyTicket)
+    {
+        if (empty($proxyTicket)) {
+            throw new CAS_InvalidArgumentException("Trying to initialize with an empty proxy ticket.");
+        }
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException('Already initialized, cannot change the proxy ticket.');
+        }
+        $this->_proxyTicket = $proxyTicket;
+    }
+
+    /**
+     * Answer the proxy ticket to be used when making requests.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before a proxy ticket has
+     * already been initialized/set.
+     */
+    protected function getProxyTicket ()
+    {
+        if (empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException('No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.');
+        }
+
+        return $this->_proxyTicket;
+    }
+
+    /**
+     * @var CAS_Client $_casClient;
+     */
+    private $_casClient;
+
+    /**
+     * Use a particular CAS_Client->initializeProxiedService() rather than the
+     * static phpCAS::initializeProxiedService().
+     *
+     * This method should not be called in standard operation, but is needed for unit
+     * testing.
+     *
+     * @param CAS_Client $casClient cas client
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized/set.
+     */
+    public function setCasClient (CAS_Client $casClient)
+    {
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException('Already initialized, cannot change the CAS_Client.');
+        }
+
+        $this->_casClient = $casClient;
+    }
+
+    /**
+     * Fetch our proxy ticket.
+     *
+     * Descendent classes should call this method once their service URL is available
+     * to initialize their proxy ticket.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has
+     * already been initialized.
+     */
+    protected function initializeProxyTicket()
+    {
+        if (!empty($this->_proxyTicket)) {
+            throw new CAS_OutOfSequenceException('Already initialized, cannot initialize again.');
+        }
+        // Allow usage of a particular CAS_Client for unit testing.
+        if (empty($this->_casClient)) {
+            phpCAS::initializeProxiedService($this);
+        } else {
+            $this->_casClient->initializeProxiedService($this);
+        }
+    }
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Exception.php b/CAS/CAS/ProxiedService/Exception.php
new file mode 100644 (file)
index 0000000..5a1e696
--- /dev/null
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An Exception for problems communicating with a proxied service.
+ *
+ * @class    CAS_ProxiedService_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Exception
+extends Exception
+implements CAS_Exception
+{
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Http.php b/CAS/CAS/ProxiedService/Http.php
new file mode 100644 (file)
index 0000000..7c9824f
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Http.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that clients should use for configuring, sending,
+ * and receiving proxied HTTP requests.
+ *
+ * @class    CAS_ProxiedService_Http
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService_Http
+{
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url);
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ();
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ();
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Http/Abstract.php b/CAS/CAS/ProxiedService/Http/Abstract.php
new file mode 100644 (file)
index 0000000..f17304c
--- /dev/null
@@ -0,0 +1,343 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Http/Abstract.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class implements common methods for ProxiedService implementations included
+ * with phpCAS.
+ *
+ * @class    CAS_ProxiedService_Http_Abstract
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_ProxiedService_Http_Abstract
+extends CAS_ProxiedService_Abstract
+implements CAS_ProxiedService_Http
+{
+    /**
+     * The HTTP request mechanism talking to the target service.
+     *
+     * @var CAS_Request_RequestInterface $requestHandler
+     */
+    protected $requestHandler;
+
+    /**
+     * The storage mechanism for cookies set by the target service.
+     *
+     * @var CAS_CookieJar $_cookieJar
+     */
+    private $_cookieJar;
+
+    /**
+     * Constructor.
+     *
+     * @param CAS_Request_RequestInterface $requestHandler request handler object
+     * @param CAS_CookieJar                $cookieJar      cookieJar object
+     *
+     * @return void
+     */
+    public function __construct (CAS_Request_RequestInterface $requestHandler, CAS_CookieJar $cookieJar)
+    {
+        $this->requestHandler = $requestHandler;
+        $this->_cookieJar = $cookieJar;
+    }
+
+    /**
+     * The target service url.
+     * @var string $_url;
+     */
+    private $_url;
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl ()
+    {
+        if (empty($this->_url)) {
+            throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->setUrl($url).');
+        }
+
+        return $this->_url;
+    }
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot set the URL, request already sent.');
+        }
+        if (!is_string($url)) {
+            throw new CAS_InvalidArgumentException('$url must be a string.');
+        }
+
+        $this->_url = $url;
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *         The code of the Exception will be one of:
+     *                 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the
+     * request to the target service.
+     */
+    public function send ()
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot send, request already sent.');
+        }
+
+        phpCAS::traceBegin();
+
+        // Get our proxy ticket and append it to our URL.
+        $this->initializeProxyTicket();
+        $url = $this->getServiceUrl();
+        if (strstr($url, '?') === false) {
+            $url = $url.'?ticket='.$this->getProxyTicket();
+        } else {
+            $url = $url.'&ticket='.$this->getProxyTicket();
+        }
+
+        try {
+            $this->makeRequest($url);
+        } catch (Exception $e) {
+            phpCAS::traceEnd();
+            throw $e;
+        }
+    }
+
+    /**
+     * Indicator of the number of requests (including redirects performed.
+     *
+     * @var int $_numRequests;
+     */
+    private $_numRequests = 0;
+
+    /**
+     * The response headers.
+     *
+     * @var array $_responseHeaders;
+     */
+    private $_responseHeaders = array();
+
+    /**
+     * The response status code.
+     *
+     * @var string $_responseStatusCode;
+     */
+    private $_responseStatusCode = '';
+
+    /**
+     * The response headers.
+     *
+     * @var string $_responseBody;
+     */
+    private $_responseBody = '';
+
+    /**
+     * Build and perform a request, following redirects
+     *
+     * @param string $url url for the request
+     *
+     * @return void
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *         The code of the Exception will be one of:
+     *                 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the
+     * request to the target service.
+     */
+    protected function makeRequest ($url)
+    {
+        // Verify that we are not in a redirect loop
+        $this->_numRequests++;
+        if ($this->_numRequests > 4) {
+            $message = 'Exceeded the maximum number of redirects (3) in proxied service request.';
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        // Create a new request.
+        $request = clone $this->requestHandler;
+        $request->setUrl($url);
+
+        // Add any cookies to the request.
+        $request->addCookies($this->_cookieJar->getCookies($url));
+
+        // Add any other parts of the request needed by concrete classes
+        $this->populateRequest($request);
+
+        // Perform the request.
+        phpCAS::trace('Performing proxied service request to \''.$url.'\'');
+        if (!$request->send()) {
+            $message = 'Could not perform proxied service request to URL`'.$url.'\'. '.$request->getErrorMessage();
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        // Store any cookies from the response;
+        $this->_cookieJar->storeCookies($url, $request->getResponseHeaders());
+
+        // Follow any redirects
+        if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())) {
+            phpCAS :: trace('Found redirect:'.$redirectUrl);
+            $this->makeRequest($redirectUrl);
+        } else {
+
+            $this->_responseHeaders = $request->getResponseHeaders();
+            $this->_responseBody = $request->getResponseBody();
+            $this->_responseStatusCode = $request->getResponseStatusCode();
+        }
+    }
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface object
+     *
+     * @return void
+     */
+    abstract protected function populateRequest (CAS_Request_RequestInterface $request);
+
+    /**
+     * Answer a redirect URL if a redirect header is found, otherwise null.
+     *
+     * @param array $responseHeaders response header to extract a redirect from
+     *
+     * @return string or null
+     */
+    protected function getRedirectUrl (array $responseHeaders)
+    {
+        // Check for the redirect after authentication
+        foreach ($responseHeaders as $header) {
+            if (preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)) {
+                return trim(array_pop($matches));
+            }
+        }
+        return null;
+    }
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer true if our request has been sent yet.
+     *
+     * @return bool
+     */
+    protected function hasBeenSent ()
+    {
+        return ($this->_numRequests > 0);
+    }
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
+        }
+
+        return $this->_responseHeaders;
+    }
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseStatusCode ()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
+        }
+
+        return $this->_responseStatusCode;
+    }
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ()
+    {
+        if (!$this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
+        }
+
+        return $this->_responseBody;
+    }
+
+    /**
+     * Answer the cookies from the response. This may include cookies set during
+     * redirect responses.
+     *
+     * @return array An array containing cookies. E.g. array('name' => 'val');
+     */
+    public function getCookies ()
+    {
+        return $this->_cookieJar->getCookies($this->getServiceUrl());
+    }
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Http/Get.php b/CAS/CAS/ProxiedService/Http/Get.php
new file mode 100644 (file)
index 0000000..01f509f
--- /dev/null
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Http/Get.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class is used to make proxied service requests via the HTTP GET method.
+ *
+ * Usage Example:
+ *
+ *                     try {
+ *                             $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
+ *                             $service->setUrl('http://www.example.com/path/');
+ *                             $service->send();
+ *                             if ($service->getResponseStatusCode() == 200)
+ *                                     return $service->getResponseBody();
+ *                             else
+ *                                     // The service responded with an error code 404, 500, etc.
+ *                                     throw new Exception('The service responded with an error.');
+ *
+ *                     } catch (CAS_ProxyTicketException $e) {
+ *                             if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
+ *                                     return "Your login has timed out. You need to log in again.";
+ *                             else
+ *                                     // Other proxy ticket errors are from bad request format (shouldn't happen)
+ *                                     // or CAS server failure (unlikely) so lets just stop if we hit those.
+ *                                     throw $e;
+ *                     } catch (CAS_ProxiedService_Exception $e) {
+ *                             // Something prevented the service request from being sent or received.
+ *                             // We didn't even get a valid error response (404, 500, etc), so this
+ *                             // might be caused by a network error or a DNS resolution failure.
+ *                             // We could handle it in some way, but for now we will just stop.
+ *                             throw $e;
+ *                     }
+ *
+ * @class    CAS_ProxiedService_Http_Get
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Http_Get
+extends CAS_ProxiedService_Http_Abstract
+{
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface
+     *
+     * @return void
+     */
+    protected function populateRequest (CAS_Request_RequestInterface $request)
+    {
+        // do nothing, since the URL has already been sent and that is our
+        // only data.
+    }
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Http/Post.php b/CAS/CAS/ProxiedService/Http/Post.php
new file mode 100644 (file)
index 0000000..643eb98
--- /dev/null
@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Http/Post.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This class is used to make proxied service requests via the HTTP POST method.
+ *
+ * Usage Example:
+ *
+ *                     try {
+ *                             $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
+ *                             $service->setUrl('http://www.example.com/path/');
+ *                             $service->setContentType('text/xml');
+ *                             $service->setBody(''<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
+ *                             $service->send();
+ *                             if ($service->getResponseStatusCode() == 200)
+ *                                     return $service->getResponseBody();
+ *                             else
+ *                                     // The service responded with an error code 404, 500, etc.
+ *                                     throw new Exception('The service responded with an error.');
+ *
+ *                     } catch (CAS_ProxyTicketException $e) {
+ *                             if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
+ *                                     return "Your login has timed out. You need to log in again.";
+ *                             else
+ *                                     // Other proxy ticket errors are from bad request format (shouldn't happen)
+ *                                     // or CAS server failure (unlikely) so lets just stop if we hit those.
+ *                                     throw $e;
+ *                     } catch (CAS_ProxiedService_Exception $e) {
+ *                             // Something prevented the service request from being sent or received.
+ *                             // We didn't even get a valid error response (404, 500, etc), so this
+ *                             // might be caused by a network error or a DNS resolution failure.
+ *                             // We could handle it in some way, but for now we will just stop.
+ *                             throw $e;
+ *                     }
+ *
+ * @class    CAS_ProxiedService_Http_Post
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Http_Post
+extends CAS_ProxiedService_Http_Abstract
+{
+
+    /**
+     * The content-type of this request
+     *
+     * @var string $_contentType
+     */
+    private $_contentType;
+
+    /**
+     * The body of the this request
+     *
+     * @var string $_body
+     */
+    private $_body;
+
+    /**
+     * Set the content type of this POST request.
+     *
+     * @param string $contentType content type
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setContentType ($contentType)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot set the content type, request already sent.');
+        }
+
+        $this->_contentType = $contentType;
+    }
+
+    /**
+     * Set the body of this POST request.
+     *
+     * @param string $body body to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setBody ($body)
+    {
+        if ($this->hasBeenSent()) {
+            throw new CAS_OutOfSequenceException('Cannot set the body, request already sent.');
+        }
+
+        $this->_body = $body;
+    }
+
+    /**
+     * Add any other parts of the request needed by concrete classes
+     *
+     * @param CAS_Request_RequestInterface $request request interface class
+     *
+     * @return void
+     */
+    protected function populateRequest (CAS_Request_RequestInterface $request)
+    {
+        if (empty($this->_contentType) && !empty($this->_body)) {
+            throw new CAS_ProxiedService_Exception("If you pass a POST body, you must specify a content type via ".get_class($this).'->setContentType($contentType).');
+        }
+
+        $request->makePost();
+        if (!empty($this->_body)) {
+            $request->addHeader('Content-Type: '.$this->_contentType);
+            $request->addHeader('Content-Length: '.strlen($this->_body));
+            $request->setPostBody($this->_body);
+        }
+    }
+
+
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Imap.php b/CAS/CAS/ProxiedService/Imap.php
new file mode 100644 (file)
index 0000000..d240d94
--- /dev/null
@@ -0,0 +1,260 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Imap.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides access to a proxy-authenticated IMAP stream
+ *
+ * @class    CAS_ProxiedService_Imap
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxiedService_Imap
+extends CAS_ProxiedService_Abstract
+{
+
+    /**
+     * The username to send via imap_open.
+     *
+     * @var string $_username;
+     */
+    private $_username;
+
+    /**
+     * Constructor.
+     *
+     * @param string $username Username
+     *
+     * @return void
+     */
+    public function __construct ($username)
+    {
+        if (!is_string($username) || !strlen($username)) {
+            throw new CAS_InvalidArgumentException('Invalid username.');
+        }
+
+        $this->_username = $username;
+    }
+
+    /**
+     * The target service url.
+     * @var string $_url;
+     */
+    private $_url;
+
+    /**
+     * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
+     *
+     * @return string
+     * @throws Exception If no service url is available.
+     */
+    public function getServiceUrl ()
+    {
+        if (empty($this->_url)) {
+            throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->getServiceUrl($url).');
+        }
+
+        return $this->_url;
+    }
+
+    /*********************************************************
+     * Configure the Stream
+    *********************************************************/
+
+    /**
+     * Set the URL of the service to pass to CAS for proxy-ticket retrieval.
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setServiceUrl ($url)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Cannot set the URL, stream already opened.');
+        }
+        if (!is_string($url) || !strlen($url)) {
+            throw new CAS_InvalidArgumentException('Invalid url.');
+        }
+
+        $this->_url = $url;
+    }
+
+    /**
+     * The mailbox to open. See the $mailbox parameter of imap_open().
+     *
+     * @var string $_mailbox
+     */
+    private $_mailbox;
+
+    /**
+     * Set the mailbox to open. See the $mailbox parameter of imap_open().
+     *
+     * @param string $mailbox Mailbox to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setMailbox ($mailbox)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Cannot set the mailbox, stream already opened.');
+        }
+        if (!is_string($mailbox) || !strlen($mailbox)) {
+            throw new CAS_InvalidArgumentException('Invalid mailbox.');
+        }
+
+        $this->_mailbox = $mailbox;
+    }
+
+    /**
+     * A bit mask of options to pass to imap_open() as the $options parameter.
+     *
+     * @var int $_options
+     */
+    private $_options = null;
+
+    /**
+     * Set the options for opening the stream. See the $options parameter of
+     * imap_open().
+     *
+     * @param int $options Options for the stream
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the stream has been opened.
+     */
+    public function setOptions ($options)
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Cannot set options, stream already opened.');
+        }
+        if (!is_int($options)) {
+            throw new CAS_InvalidArgumentException('Invalid options.');
+        }
+
+        $this->_options = $options;
+    }
+
+    /*********************************************************
+     * 2. Open the stream
+    *********************************************************/
+
+    /**
+     * Open the IMAP stream (similar to imap_open()).
+     *
+     * @return resource Returns an IMAP stream on success
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
+     *         The code of the Exception will be one of:
+     *                 PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
+     *                 PHPCAS_SERVICE_PT_FAILURE
+     * @throws CAS_ProxiedService_Exception If there is a failure sending the request to the target service.    */
+    public function open ()
+    {
+        if ($this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Stream already opened.');
+        }
+        if (empty($this->_mailbox)) {
+            throw new CAS_ProxiedService_Exception('You must specify a mailbox via '.get_class($this).'->setMailbox($mailbox)');
+        }
+
+        phpCAS::traceBegin();
+
+        // Get our proxy ticket and append it to our URL.
+        $this->initializeProxyTicket();
+        phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...');
+        $this->_stream = @imap_open($this->_mailbox, $this->_username, $this->getProxyTicket(), $this->_options);
+        if ($this->_stream) {
+            phpCAS::trace('ok');
+        } else {
+            phpCAS::trace('could not open mailbox');
+            // @todo add localization integration.
+            $message = 'IMAP Error: '.$url.' '. var_export(imap_errors(), true);
+            phpCAS::trace($message);
+            throw new CAS_ProxiedService_Exception($message);
+        }
+
+        phpCAS::traceEnd();
+        return $this->_stream;
+    }
+
+    /**
+     * Answer true if our request has been sent yet.
+     *
+     * @return bool
+     */
+    protected function hasBeenOpened ()
+    {
+        return !empty($this->_stream);
+    }
+
+    /*********************************************************
+     * 3. Access the result
+    *********************************************************/
+    /**
+     * The IMAP stream
+     *
+     * @var resource $_stream
+     */
+    private $_stream;
+
+    /**
+     * Answer the IMAP stream
+     *
+     * @return resource
+     */
+    public function getStream ()
+    {
+        if (!$this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Cannot access stream, not opened yet.');
+        }
+        return $this->_stream;
+    }
+
+    /**
+     * CAS_Client::serviceMail() needs to return the proxy ticket for some reason,
+     * so this method provides access to it.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the stream has been
+     * opened.
+     */
+    public function getImapProxyTicket ()
+    {
+        if (!$this->hasBeenOpened()) {
+            throw new CAS_OutOfSequenceException('Cannot access errors, stream not opened yet.');
+        }
+        return $this->getProxyTicket();
+    }
+}
+?>
diff --git a/CAS/CAS/ProxiedService/Testable.php b/CAS/CAS/ProxiedService/Testable.php
new file mode 100644 (file)
index 0000000..a2f6fca
--- /dev/null
@@ -0,0 +1,73 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxiedService/Testabel.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines methods that allow proxy-authenticated service handlers
+ * to be tested in unit tests.
+ *
+ * Classes implementing this interface SHOULD store the CAS_Client passed and initialize
+ * themselves with that client rather than via the static phpCAS method. For example:
+ *
+ *             / **
+ *              * Fetch our proxy ticket.
+ *              * /
+ *             protected function initializeProxyTicket() {
+ *                     // Allow usage of a particular CAS_Client for unit testing.
+ *                     if (is_null($this->casClient))
+ *                             phpCAS::initializeProxiedService($this);
+ *                     else
+ *                             $this->casClient->initializeProxiedService($this);
+ *             }
+ *
+ * @class    CAS_ProxiedService_Testabel
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxiedService_Testable
+{
+
+    /**
+     * Use a particular CAS_Client->initializeProxiedService() rather than the
+     * static phpCAS::initializeProxiedService().
+     *
+     * This method should not be called in standard operation, but is needed for unit
+     * testing.
+     *
+     * @param CAS_Client $casClient Cas client object
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
+     */
+    public function setCasClient (CAS_Client $casClient);
+
+}
+?>
diff --git a/CAS/CAS/ProxyChain.php b/CAS/CAS/ProxyChain.php
new file mode 100644 (file)
index 0000000..01ce73d
--- /dev/null
@@ -0,0 +1,118 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxyChain.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A normal proxy-chain definition that lists each level of the chain as either
+ * a string or regular expression.
+ *
+ * @class    CAS_ProxyChain
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_ProxyChain
+implements CAS_ProxyChain_Interface
+{
+
+    protected $chain = array();
+
+    /**
+     * A chain is an array of strings or regexp strings that will be matched
+     * against. Regexp will be matched with preg_match and strings will be
+     * matched from the beginning. A string must fully match the beginning of
+     * an proxy url. So you can define a full domain as acceptable or go further
+     * down.
+     * Proxies have to be defined in reverse from the service to the user. If a
+     * user hits service A get proxied via B to service C the list of acceptable
+     * proxies on C would be array(B,A);
+     *
+     * @param array $chain A chain of proxies
+     */
+    public function __construct(array $chain)
+    {
+        $this->chain = array_values($chain);   // Ensure that we have an indexed array
+    }
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list)
+    {
+        $list = array_values($list);  // Ensure that we have an indexed array
+        if ($this->isSizeValid($list)) {
+            $mismatch = false;
+            foreach ($this->chain as $i => $search) {
+                $proxy_url = $list[$i];
+                if (preg_match('/^\/.*\/[ixASUXu]*$/s', $search)) {
+                    if (preg_match($search, $proxy_url)) {
+                        phpCAS::trace("Found regexp " .  $search . " matching " . $proxy_url);
+                    } else {
+                        phpCAS::trace("No regexp match " .  $search . " != " . $proxy_url);
+                        $mismatch = true;
+                        break;
+                    }
+                } else {
+                    if (strncasecmp($search, $proxy_url, strlen($search)) == 0) {
+                        phpCAS::trace("Found string " .  $search . " matching " . $proxy_url);
+                    } else {
+                        phpCAS::trace("No match " .  $search . " != " . $proxy_url);
+                        $mismatch = true;
+                        break;
+                    }
+                }
+            }
+            if (!$mismatch) {
+                phpCAS::trace("Proxy chain matches");
+                return true;
+            }
+        } else {
+            phpCAS::trace("Proxy chain skipped: size mismatch");
+        }
+        return false;
+    }
+
+    /**
+     * Validate the size of the the list as compared to our chain.
+     *
+     * @param array $list List of proxies
+     *
+     * @return bool
+     */
+    protected function isSizeValid (array $list)
+    {
+        return (sizeof($this->chain) == sizeof($list));
+    }
+}
diff --git a/CAS/CAS/ProxyChain/AllowedList.php b/CAS/CAS/ProxyChain/AllowedList.php
new file mode 100644 (file)
index 0000000..62d196a
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxyChain/AllowedList.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+
+/**
+ * ProxyChain is a container for storing chains of valid proxies that can
+ * be used to validate proxied requests to a service
+ *
+ * @class    CAS_ProxyChain_AllowedList
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+class CAS_ProxyChain_AllowedList
+{
+
+    private $_chains = array();
+
+    /**
+     * Check whether proxies are allowed by configuration
+     *
+     * @return bool
+     */
+    public function isProxyingAllowed()
+    {
+        return (count($this->_chains) > 0);
+    }
+
+    /**
+     * Add a chain of proxies to the list of possible chains
+     *
+     * @param CAS_ProxyChain_Interface $chain A chain of proxies
+     *
+     * @return void
+     */
+    public function allowProxyChain(CAS_ProxyChain_Interface $chain)
+    {
+        $this->_chains[] = $chain;
+    }
+
+    /**
+     * Check if the proxies found in the response match the allowed proxies
+     *
+     * @param array $proxies list of proxies to check
+     *
+     * @return bool whether the proxies match the allowed proxies
+     */
+    public function isProxyListAllowed(array $proxies)
+    {
+        phpCAS::traceBegin();
+        if (empty($proxies)) {
+            phpCAS::trace("No proxies were found in the response");
+            phpCAS::traceEnd(true);
+            return true;
+        } elseif (!$this->isProxyingAllowed()) {
+            phpCAS::trace("Proxies are not allowed");
+            phpCAS::traceEnd(false);
+            return false;
+        } else {
+            $res = $this->contains($proxies);
+            phpCAS::traceEnd($res);
+            return $res;
+        }
+    }
+
+    /**
+     * Validate the proxies from the proxy ticket validation against the
+     * chains that were definded.
+     *
+     * @param array $list List of proxies from the proxy ticket validation.
+     *
+     * @return if any chain fully matches the supplied list
+     */
+    public function contains(array $list)
+    {
+        phpCAS::traceBegin();
+        $count = 0;
+        foreach ($this->_chains as $chain) {
+            phpCAS::trace("Checking chain ". $count++);
+            if ($chain->matches($list)) {
+                phpCAS::traceEnd(true);
+                return true;
+            }
+        }
+        phpCAS::trace("No proxy chain matches.");
+        phpCAS::traceEnd(false);
+        return false;
+    }
+}
+?>
diff --git a/CAS/CAS/ProxyChain/Any.php b/CAS/CAS/ProxyChain/Any.php
new file mode 100644 (file)
index 0000000..0cd92f7
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxyChain/Any.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A proxy-chain definition that will match any list of proxies.
+ *
+ * Use this class for quick testing or in certain production screnarios you
+ * might want to allow allow any other valid service to proxy your service.
+ *
+ * THIS CLASS IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+ * IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+ * ON THIS SERVICE.
+ *
+ * @class    CAS_ProxyChain_Any
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyChain_Any
+implements CAS_ProxyChain_Interface
+{
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list)
+    {
+        phpCAS::trace("Using CAS_ProxyChain_Any. No proxy validation is performed.");
+        return true;
+    }
+
+}
diff --git a/CAS/CAS/ProxyChain/Interface.php b/CAS/CAS/ProxyChain/Interface.php
new file mode 100644 (file)
index 0000000..d247115
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxyChain/Interface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An interface for classes that define a list of allowed proxies in front of
+ * the current application.
+ *
+ * @class    CAS_ProxyChain_Interface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_ProxyChain_Interface
+{
+
+    /**
+     * Match a list of proxies.
+     *
+     * @param array $list The list of proxies in front of this service.
+     *
+     * @return bool
+     */
+    public function matches(array $list);
+
+}
\ No newline at end of file
diff --git a/CAS/CAS/ProxyChain/Trusted.php b/CAS/CAS/ProxyChain/Trusted.php
new file mode 100644 (file)
index 0000000..7fa6129
--- /dev/null
@@ -0,0 +1,59 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/ProxyChain/Trusted.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * A proxy-chain definition that defines a chain up to a trusted proxy and
+ * delegates the resposibility of validating the rest of the chain to that
+ * trusted proxy.
+ *
+ * @class    CAS_ProxyChain_Trusted
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyChain_Trusted
+extends CAS_ProxyChain
+implements CAS_ProxyChain_Interface
+{
+
+    /**
+     * Validate the size of the the list as compared to our chain.
+     *
+     * @param array $list list of proxies
+     *
+     * @return bool
+     */
+    protected function isSizeValid (array $list)
+    {
+        return (sizeof($this->chain) <= sizeof($list));
+    }
+
+}
diff --git a/CAS/CAS/ProxyTicketException.php b/CAS/CAS/ProxyTicketException.php
new file mode 100644 (file)
index 0000000..57df81f
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @class    CAS/ProxyTicketException.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ *
+ */
+
+/**
+ * An Exception for errors related to fetching or validating proxy tickets.
+ *
+ * @class    CAS_ProxyTicketException
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_ProxyTicketException
+extends BadMethodCallException
+implements CAS_Exception
+{
+
+    /**
+     * Constructor
+     *
+     * @param string $message Message text
+     * @param int    $code    Error code
+     *
+     * @return void
+     */
+    public function __construct ($message, $code = PHPCAS_SERVICE_PT_FAILURE)
+    {
+        // Warn if the code is not in our allowed list
+        $ptCodes = array(
+        PHPCAS_SERVICE_PT_FAILURE,
+        PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE,
+        PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
+        );
+        if (!in_array($code, $ptCodes)) {
+            trigger_error('Invalid code '.$code.' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.');
+        }
+
+        parent::__construct($message, $code);
+    }
+}
diff --git a/CAS/CAS/Request/AbstractRequest.php b/CAS/CAS/Request/AbstractRequest.php
new file mode 100644 (file)
index 0000000..0f2e467
--- /dev/null
@@ -0,0 +1,343 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/AbstractRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides support for performing web-requests via curl
+ *
+ * @class    CAS_Request_AbstractRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+abstract class CAS_Request_AbstractRequest
+implements CAS_Request_RequestInterface
+{
+
+    protected $url = null;
+    protected $cookies = array();
+    protected $headers = array();
+    protected $isPost = false;
+    protected $postBody = null;
+    protected $caCertPath = null;
+    protected $validateCN = true;
+    private $_sent = false;
+    private $_responseHeaders = array();
+    private $_responseBody = null;
+    private $_errorMessage = '';
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url Url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->url = $url;
+    }
+
+    /**
+     * Add a cookie to the request.
+     *
+     * @param string $name  Name of entry
+     * @param string $value value of entry
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookie ($name, $value)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->cookies[$name] = $value;
+    }
+
+    /**
+     * Add an array of cookies to the request.
+     * The cookie array is of the form
+     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')
+     *
+     * @param array $cookies cookies to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookies (array $cookies)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->cookies = array_merge($this->cookies, $cookies);
+    }
+
+    /**
+     * Add a header string to the request.
+     *
+     * @param string $header Header to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeader ($header)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->headers[] = $header;
+    }
+
+    /**
+     * Add an array of header strings to the request.
+     *
+     * @param array $headers headers to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeaders (array $headers)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->headers = array_merge($this->headers, $headers);
+    }
+
+    /**
+     * Make the request a POST request rather than the default GET request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function makePost ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+
+        $this->isPost = true;
+    }
+
+    /**
+     * Add a POST body to the request
+     *
+     * @param string $body body to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setPostBody ($body)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+        if (!$this->isPost) {
+            throw new CAS_OutOfSequenceException('Cannot add a POST body to a GET request, use makePost() first.');
+        }
+
+        $this->postBody = $body;
+    }
+
+    /**
+     * Specify the path to an SSL CA certificate to validate the server with.
+     *
+     * @param string $caCertPath  path to cert
+     * @param bool   $validate_cn valdiate CN of certificate
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setSslCaCert ($caCertPath,$validate_cn=true)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+        $this->caCertPath = $caCertPath;
+        $this->validateCN = $validate_cn;
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
+        }
+        if (is_null($this->url) || !$this->url) {
+            throw new CAS_OutOfSequenceException('A url must be specified via setUrl() before the request can be sent.');
+        }
+        $this->_sent = true;
+        return $this->sendRequest();
+    }
+
+    /**
+     * Send the request and store the results.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     */
+    abstract protected function sendRequest ();
+
+    /**
+     * Store the response headers.
+     *
+     * @param array $headers headers to store
+     *
+     * @return void
+     */
+    protected function storeResponseHeaders (array $headers)
+    {
+        $this->_responseHeaders = array_merge($this->_responseHeaders, $headers);
+    }
+
+    /**
+     * Store a single response header to our array.
+     *
+     * @param string $header header to store
+     *
+     * @return void
+     */
+    protected function storeResponseHeader ($header)
+    {
+        $this->_responseHeaders[] = $header;
+    }
+
+    /**
+     * Store the response body.
+     *
+     * @param string $body body to store
+     *
+     * @return void
+     */
+    protected function storeResponseBody ($body)
+    {
+        $this->_responseBody = $body;
+    }
+
+    /**
+     * Add a string to our error message.
+     *
+     * @param string $message message to add
+     *
+     * @return void
+     */
+    protected function storeErrorMessage ($message)
+    {
+        $this->_errorMessage .= $message;
+    }
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
+        }
+        return $this->_responseHeaders;
+    }
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseStatusCode ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
+        }
+
+        if (!preg_match('/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/', $this->_responseHeaders[0], $matches)) {
+            throw new CAS_Request_Exception("Bad response, no status code was found in the first line.");
+        }
+
+        return intval($matches[1]);
+    }
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
+        }
+
+        return $this->_responseBody;
+    }
+
+    /**
+     * Answer a message describing any errors if the request failed.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getErrorMessage ()
+    {
+        if (!$this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
+        }
+        return $this->_errorMessage;
+    }
+}
diff --git a/CAS/CAS/Request/CurlMultiRequest.php b/CAS/CAS/Request/CurlMultiRequest.php
new file mode 100644 (file)
index 0000000..a046989
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/AbstractRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing multiple web requests
+ * in batches. Implementations of this interface may perform requests serially
+ * or in parallel.
+ *
+ * @class    CAS_Request_CurlMultiRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_CurlMultiRequest
+implements CAS_Request_MultiRequestInterface
+{
+    private $_requests = array();
+    private $_sent = false;
+
+    /*********************************************************
+     * Add Requests
+    *********************************************************/
+
+    /**
+     * Add a new Request to this batch.
+     * Note, implementations will likely restrict requests to their own concrete
+     * class hierarchy.
+     *
+     * @param CAS_Request_RequestInterface $request reqest to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     * @throws CAS_InvalidArgumentException If passed a Request of the wrong
+     * implmentation.
+     */
+    public function addRequest (CAS_Request_RequestInterface $request)
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+        if (!$request instanceof CAS_Request_CurlRequest) {
+            throw new CAS_InvalidArgumentException('As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.');
+        }
+
+        $this->_requests[] = $request;
+    }
+
+    /**
+     * Retrieve the number of requests added to this batch.
+     *
+     * @return number of request elements
+     */
+    public function getNumRequests()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
+        }
+        return count($this->_requests);
+    }
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request. After sending, all requests will have their
+     * responses poulated.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ()
+    {
+        if ($this->_sent) {
+            throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
+        }
+        if (!count($this->_requests)) {
+            throw new CAS_OutOfSequenceException('At least one request must be added via addRequest() before the multi-request can be sent.');
+        }
+
+        $this->_sent = true;
+
+        // Initialize our handles and configure all requests.
+        $handles = array();
+        $multiHandle = curl_multi_init();
+        foreach ($this->_requests as $i => $request) {
+            $handle = $request->_initAndConfigure();
+            curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
+            $handles[$i] = $handle;
+            curl_multi_add_handle($multiHandle, $handle);
+        }
+
+        // Execute the requests in parallel.
+        do {
+            curl_multi_exec($multiHandle, $running);
+        } while ($running > 0);
+
+        // Populate all of the responses or errors back into the request objects.
+        foreach ($this->_requests as $i => $request) {
+            $buf = curl_multi_getcontent($handles[$i]);
+            $request->_storeResponseBody($buf);
+            curl_multi_remove_handle($multiHandle, $handles[$i]);
+            curl_close($handles[$i]);
+        }
+
+        curl_multi_close($multiHandle);
+    }
+}
diff --git a/CAS/CAS/Request/CurlRequest.php b/CAS/CAS/Request/CurlRequest.php
new file mode 100644 (file)
index 0000000..e20914f
--- /dev/null
@@ -0,0 +1,197 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/CurlRequest.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * Provides support for performing web-requests via curl
+ *
+ * @class    CAS_Request_CurlRequest
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_CurlRequest
+extends CAS_Request_AbstractRequest
+implements CAS_Request_RequestInterface
+{
+
+    /**
+     * Set additional curl options
+     *
+     * @param array $options option to set
+     *
+     * @return void
+     */
+    public function setCurlOptions (array $options)
+    {
+        $this->_curlOptions = $options;
+    }
+    private $_curlOptions = array();
+
+    /**
+     * Send the request and store the results.
+     *
+     * @return bool true on success, false on failure.
+     */
+    protected function sendRequest ()
+    {
+        phpCAS::traceBegin();
+
+        /*********************************************************
+         * initialize the CURL session
+        *********************************************************/
+        $ch = $this->_initAndConfigure();
+
+        /*********************************************************
+         * Perform the query
+        *********************************************************/
+        $buf = curl_exec($ch);
+        if ( $buf === false ) {
+            phpCAS::trace('curl_exec() failed');
+            $this->storeErrorMessage('CURL error #'.curl_errno($ch).': '.curl_error($ch));
+            $res = false;
+        } else {
+            $this->storeResponseBody($buf);
+            phpCAS::trace("Response Body: \n".$buf."\n");
+            $res = true;
+
+        }
+        // close the CURL session
+        curl_close($ch);
+
+        phpCAS::traceEnd($res);
+        return $res;
+    }
+
+    /**
+     * Internal method to initialize our cURL handle and configure the request.
+     * This method should NOT be used outside of the CurlRequest or the
+     * CurlMultiRequest.
+     *
+     * @return resource The cURL handle on success, false on failure
+     */
+    private function _initAndConfigure()
+    {
+        /*********************************************************
+         * initialize the CURL session
+        *********************************************************/
+        $ch = curl_init($this->url);
+
+        if (version_compare(PHP_VERSION, '5.1.3', '>=')) {
+            //only avaible in php5
+            curl_setopt_array($ch, $this->_curlOptions);
+        } else {
+            foreach ($this->_curlOptions as $key => $value) {
+                curl_setopt($ch, $key, $value);
+            }
+        }
+
+        /*********************************************************
+         * Set SSL configuration
+        *********************************************************/
+        if ($this->caCertPath) {
+            if ($this->validateCN) {
+                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+            } else {
+                curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
+            }
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
+            curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath);
+            phpCAS::trace('CURL: Set CURLOPT_CAINFO ' . $this->caCertPath);
+        } else {
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+        }
+
+        /*********************************************************
+         * Configure curl to capture our output.
+        *********************************************************/
+        // return the CURL output into a variable
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+
+        // get the HTTP header with a callback
+        curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curlReadHeaders'));
+
+        /*********************************************************
+         * Add cookie headers to our request.
+        *********************************************************/
+        if (count($this->cookies)) {
+            $cookieStrings = array();
+            foreach ($this->cookies as $name => $val) {
+                $cookieStrings[] = $name.'='.$val;
+            }
+            curl_setopt($ch, CURLOPT_COOKIE, implode(';', $cookieStrings));
+        }
+
+        /*********************************************************
+         * Add any additional headers
+        *********************************************************/
+        if (count($this->headers)) {
+            curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
+        }
+
+        /*********************************************************
+         * Flag and Body for POST requests
+        *********************************************************/
+        if ($this->isPost) {
+            curl_setopt($ch, CURLOPT_POST, 1);
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->postBody);
+        }
+
+        return $ch;
+    }
+
+    /**
+     * Store the response body.
+     * This method should NOT be used outside of the CurlRequest or the
+     * CurlMultiRequest.
+     *
+     * @param string $body body to stor
+     *
+     * @return void
+     */
+    private function _storeResponseBody ($body)
+    {
+        $this->storeResponseBody($body);
+    }
+
+    /**
+     * Internal method for capturing the headers from a curl request.
+     *
+     * @param handle $ch     handle of curl
+     * @param string $header header
+     *
+     * @return void
+     */
+    private function _curlReadHeaders ($ch, $header)
+    {
+        $this->storeResponseHeader($header);
+        return strlen($header);
+    }
+}
diff --git a/CAS/CAS/Request/Exception.php b/CAS/CAS/Request/Exception.php
new file mode 100644 (file)
index 0000000..14ff3c6
--- /dev/null
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/Exception.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * An Exception for problems performing requests
+ *
+ * @class    CAS_Request_Exception
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+class CAS_Request_Exception
+extends Exception
+implements CAS_Exception
+{
+
+}
diff --git a/CAS/CAS/Request/MultiRequestInterface.php b/CAS/CAS/Request/MultiRequestInterface.php
new file mode 100644 (file)
index 0000000..abc4486
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/MultiRequestInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing multiple web requests
+ * in batches. Implementations of this interface may perform requests serially
+ * or in parallel.
+ *
+ * @class    CAS_Request_MultiRequestInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_Request_MultiRequestInterface
+{
+
+    /*********************************************************
+     * Add Requests
+    *********************************************************/
+
+    /**
+     * Add a new Request to this batch.
+     * Note, implementations will likely restrict requests to their own concrete
+     * class hierarchy.
+     *
+     * @param CAS_Request_RequestInterface $request request interface
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been
+     * sent.
+     * @throws CAS_InvalidArgumentException If passed a Request of the wrong
+     * implmentation.
+     */
+    public function addRequest (CAS_Request_RequestInterface $request);
+
+    /**
+     * Retrieve the number of requests added to this batch.
+     *
+     * @return number of request elements
+     */
+    public function getNumRequests ();
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request. After sending, all requests will have their
+     * responses poulated.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+}
diff --git a/CAS/CAS/Request/RequestInterface.php b/CAS/CAS/Request/RequestInterface.php
new file mode 100644 (file)
index 0000000..cc11ba4
--- /dev/null
@@ -0,0 +1,179 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/Request/RequestInterface.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+/**
+ * This interface defines a class library for performing web requests.
+ *
+ * @class    CAS_Request_RequestInterface
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+interface CAS_Request_RequestInterface
+{
+
+    /*********************************************************
+     * Configure the Request
+    *********************************************************/
+
+    /**
+     * Set the URL of the Request
+     *
+     * @param string $url url to set
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setUrl ($url);
+
+    /**
+     * Add a cookie to the request.
+     *
+     * @param string $name  name of cookie
+     * @param string $value value of cookie
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookie ($name, $value);
+
+    /**
+     * Add an array of cookies to the request.
+     * The cookie array is of the form
+     *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')
+     *
+     * @param array $cookies cookies to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addCookies (array $cookies);
+
+    /**
+     * Add a header string to the request.
+     *
+     * @param string $header header to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeader ($header);
+
+    /**
+     * Add an array of header strings to the request.
+     *
+     * @param array $headers headers to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function addHeaders (array $headers);
+
+    /**
+     * Make the request a POST request rather than the default GET request.
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function makePost ();
+
+    /**
+     * Add a POST body to the request
+     *
+     * @param string $body body to add
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setPostBody ($body);
+
+
+    /**
+     * Specify the path to an SSL CA certificate to validate the server with.
+     *
+     * @param string  $caCertPath  path to cert file
+     * @param boolean $validate_cn validate CN of SSL certificate
+     *
+     * @return void
+     * @throws CAS_OutOfSequenceException If called after the Request has been sent.
+     */
+    public function setSslCaCert ($caCertPath, $validate_cn = true);
+
+
+
+    /*********************************************************
+     * 2. Send the Request
+    *********************************************************/
+
+    /**
+     * Perform the request.
+     *
+     * @return bool TRUE on success, FALSE on failure.
+     * @throws CAS_OutOfSequenceException If called multiple times.
+     */
+    public function send ();
+
+    /*********************************************************
+     * 3. Access the response
+    *********************************************************/
+
+    /**
+     * Answer the headers of the response.
+     *
+     * @return array An array of header strings.
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseHeaders ();
+
+    /**
+     * Answer HTTP status code of the response
+     *
+     * @return int
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseStatusCode ();
+
+    /**
+     * Answer the body of response.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getResponseBody ();
+
+    /**
+     * Answer a message describing any errors if the request failed.
+     *
+     * @return string
+     * @throws CAS_OutOfSequenceException If called before the Request has been sent.
+     */
+    public function getErrorMessage ();
+}
diff --git a/CAS/CAS/client.php b/CAS/CAS/client.php
deleted file mode 100644 (file)
index 74d6893..0000000
+++ /dev/null
@@ -1,2776 +0,0 @@
-<?php
-
-/*
- * Copyright © 2003-2010, The ESUP-Portail consortium & the JA-SIG Collaborative.
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 
- *     * Redistributions of source code must retain the above copyright notice,
- *       this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright notice,
- *       this list of conditions and the following disclaimer in the documentation
- *       and/or other materials provided with the distribution.
- *     * Neither the name of the ESUP-Portail consortium & the JA-SIG
- *       Collaborative nor the names of its contributors may be used to endorse or
- *       promote products derived from this software without specific prior
- *       written permission.
-
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * @file CAS/client.php
- * Main class of the phpCAS library
- */
-
-// include internationalization stuff
-include_once(dirname(__FILE__).'/languages/languages.php');
-
-// include PGT storage classes
-include_once(dirname(__FILE__).'/PGTStorage/pgt-main.php');
-
-/**
- * @class CASClient
- * The CASClient class is a client interface that provides CAS authentication
- * to PHP applications.
- *
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>
- */
-
-class CASClient
-{
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                          CONFIGURATION                             XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       // ########################################################################
-       //  HTML OUTPUT
-       // ########################################################################
-       /**
-        * @addtogroup internalOutput
-        * @{
-        */  
-       
-       /**
-        * This method filters a string by replacing special tokens by appropriate values
-        * and prints it. The corresponding tokens are taken into account:
-        * - __CAS_VERSION__
-        * - __PHPCAS_VERSION__
-        * - __SERVER_BASE_URL__
-        *
-        * Used by CASClient::PrintHTMLHeader() and CASClient::printHTMLFooter().
-        *
-        * @param $str the string to filter and output
-        *
-        * @private
-        */
-       function HTMLFilterOutput($str)
-               {
-               $str = str_replace('__CAS_VERSION__',$this->getServerVersion(),$str);
-               $str = str_replace('__PHPCAS_VERSION__',phpCAS::getVersion(),$str);
-               $str = str_replace('__SERVER_BASE_URL__',$this->getServerBaseURL(),$str);
-               echo $str;
-               }
-       
-       /**
-        * A string used to print the header of HTML pages. Written by CASClient::setHTMLHeader(),
-        * read by CASClient::printHTMLHeader().
-        *
-        * @hideinitializer
-        * @private
-        * @see CASClient::setHTMLHeader, CASClient::printHTMLHeader()
-        */
-       var $_output_header = '';
-       
-       /**
-        * This method prints the header of the HTML output (after filtering). If
-        * CASClient::setHTMLHeader() was not used, a default header is output.
-        *
-        * @param $title the title of the page
-        *
-        * @see HTMLFilterOutput()
-        * @private
-        */
-       function printHTMLHeader($title)
-               {
-               $this->HTMLFilterOutput(str_replace('__TITLE__',
-                       $title,
-                       (empty($this->_output_header)
-                                       ? '<html><head><title>__TITLE__</title></head><body><h1>__TITLE__</h1>'
-                                                       : $this->_output_header)
-               )
-               );
-               }
-       
-       /**
-        * A string used to print the footer of HTML pages. Written by CASClient::setHTMLFooter(),
-        * read by printHTMLFooter().
-        *
-        * @hideinitializer
-        * @private
-        * @see CASClient::setHTMLFooter, CASClient::printHTMLFooter()
-        */
-       var $_output_footer = '';
-       
-       /**
-        * This method prints the footer of the HTML output (after filtering). If
-        * CASClient::setHTMLFooter() was not used, a default footer is output.
-        *
-        * @see HTMLFilterOutput()
-        * @private
-        */
-       function printHTMLFooter()
-               {
-               $this->HTMLFilterOutput(empty($this->_output_footer)
-                       ?('<hr><address>phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' <a href="__SERVER_BASE_URL__">__SERVER_BASE_URL__</a> (CAS __CAS_VERSION__)</a></address></body></html>')
-                                       :$this->_output_footer);
-               }
-       
-       /**
-        * This method set the HTML header used for all outputs.
-        *
-        * @param $header the HTML header.
-        *
-        * @public
-        */
-       function setHTMLHeader($header)
-               {
-               $this->_output_header = $header;
-               }
-       
-       /**
-        * This method set the HTML footer used for all outputs.
-        *
-        * @param $footer the HTML footer.
-        *
-        * @public
-        */
-       function setHTMLFooter($footer)
-               {
-               $this->_output_footer = $footer;
-               }
-       
-       /** @} */
-       // ########################################################################
-       //  INTERNATIONALIZATION
-       // ########################################################################
-       /**
-        * @addtogroup internalLang
-        * @{
-        */  
-       /**
-        * A string corresponding to the language used by phpCAS. Written by 
-        * CASClient::setLang(), read by CASClient::getLang().
-        
-        * @note debugging information is always in english (debug purposes only).
-        *
-        * @hideinitializer
-        * @private
-        * @sa CASClient::_strings, CASClient::getString()
-        */
-       var $_lang = '';
-       
-       /**
-        * This method returns the language used by phpCAS.
-        *
-        * @return a string representing the language
-        *
-        * @private
-        */
-       function getLang()
-               {
-               if ( empty($this->_lang) )
-                       $this->setLang(PHPCAS_LANG_DEFAULT);
-               return $this->_lang;
-               }
-       
-       /**
-        * array containing the strings used by phpCAS. Written by CASClient::setLang(), read by 
-        * CASClient::getString() and used by CASClient::setLang().
-        *
-        * @note This array is filled by instructions in CAS/languages/<$this->_lang>.php
-        *
-        * @private
-        * @see CASClient::_lang, CASClient::getString(), CASClient::setLang(), CASClient::getLang()
-        */
-       var $_strings;
-       
-       /**
-        * This method returns a string depending on the language.
-        *
-        * @param $str the index of the string in $_string.
-        *
-        * @return the string corresponding to $index in $string.
-        *
-        * @private
-        */
-       function getString($str)
-               {
-               // call CASclient::getLang() to be sure the language is initialized
-               $this->getLang();
-               
-               if ( !isset($this->_strings[$str]) ) {
-                       trigger_error('string `'.$str.'\' not defined for language `'.$this->getLang().'\'',E_USER_ERROR);
-               }
-               return $this->_strings[$str];
-               }
-       
-       /**
-        * This method is used to set the language used by phpCAS. 
-        * @note Can be called only once.
-        *
-        * @param $lang a string representing the language.
-        *
-        * @public
-        * @sa CAS_LANG_FRENCH, CAS_LANG_ENGLISH
-        */
-       function setLang($lang)
-               {
-               // include the corresponding language file
-               include_once(dirname(__FILE__).'/languages/'.$lang.'.php');
-               
-               if ( !is_array($this->_strings) ) {
-                       trigger_error('language `'.$lang.'\' is not implemented',E_USER_ERROR);
-               }
-               $this->_lang = $lang;
-               }
-       
-       /** @} */
-       // ########################################################################
-       //  CAS SERVER CONFIG
-       // ########################################################################
-       /**
-        * @addtogroup internalConfig
-        * @{
-        */  
-       
-       /**
-        * a record to store information about the CAS server.
-        * - $_server["version"]: the version of the CAS server
-        * - $_server["hostname"]: the hostname of the CAS server
-        * - $_server["port"]: the port the CAS server is running on
-        * - $_server["uri"]: the base URI the CAS server is responding on
-        * - $_server["base_url"]: the base URL of the CAS server
-        * - $_server["login_url"]: the login URL of the CAS server
-        * - $_server["service_validate_url"]: the service validating URL of the CAS server
-        * - $_server["proxy_url"]: the proxy URL of the CAS server
-        * - $_server["proxy_validate_url"]: the proxy validating URL of the CAS server
-        * - $_server["logout_url"]: the logout URL of the CAS server
-        *
-        * $_server["version"], $_server["hostname"], $_server["port"] and $_server["uri"]
-        * are written by CASClient::CASClient(), read by CASClient::getServerVersion(), 
-        * CASClient::getServerHostname(), CASClient::getServerPort() and CASClient::getServerURI().
-        *
-        * The other fields are written and read by CASClient::getServerBaseURL(), 
-        * CASClient::getServerLoginURL(), CASClient::getServerServiceValidateURL(), 
-        * CASClient::getServerProxyValidateURL() and CASClient::getServerLogoutURL().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_server = array(
-               'version' => -1,
-               'hostname' => 'none',
-               'port' => -1,
-               'uri' => 'none'
-       );
-       
-       /**
-        * This method is used to retrieve the version of the CAS server.
-        * @return the version of the CAS server.
-        * @private
-        */
-       function getServerVersion()
-               { 
-               return $this->_server['version']; 
-               }
-       
-       /**
-        * This method is used to retrieve the hostname of the CAS server.
-        * @return the hostname of the CAS server.
-        * @private
-        */
-       function getServerHostname()
-               { return $this->_server['hostname']; }
-       
-       /**
-        * This method is used to retrieve the port of the CAS server.
-        * @return the port of the CAS server.
-        * @private
-        */
-       function getServerPort()
-               { return $this->_server['port']; }
-       
-       /**
-        * This method is used to retrieve the URI of the CAS server.
-        * @return a URI.
-        * @private
-        */
-       function getServerURI()
-               { return $this->_server['uri']; }
-       
-       /**
-        * This method is used to retrieve the base URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerBaseURL()
-               { 
-                       // the URL is build only when needed
-                       if ( empty($this->_server['base_url']) ) {
-                               $this->_server['base_url'] = 'https://' . $this->getServerHostname();
-                               if ($this->getServerPort()!=443) {
-                                       $this->_server['base_url'] .= ':'
-                                       .$this->getServerPort();
-                               }
-                               $this->_server['base_url'] .= $this->getServerURI();
-                       }
-                       return $this->_server['base_url'];
-               }
-       
-       /**
-        * This method is used to retrieve the login URL of the CAS server.
-        * @param $gateway true to check authentication, false to force it
-        * @param $renew true to force the authentication with the CAS server
-        * NOTE : It is recommended that CAS implementations ignore the
-        "gateway" parameter if "renew" is set
-        * @return a URL.
-        * @private
-        */
-       function getServerLoginURL($gateway=false,$renew=false) {
-               phpCAS::traceBegin();
-               // the URL is build only when needed
-               if ( empty($this->_server['login_url']) ) {
-                       $this->_server['login_url'] = $this->getServerBaseURL();
-                       $this->_server['login_url'] .= 'login?service=';
-                       // $this->_server['login_url'] .= preg_replace('/&/','%26',$this->getURL());
-                       $this->_server['login_url'] .= urlencode($this->getURL());
-                       if($renew) {
-                               // It is recommended that when the "renew" parameter is set, its value be "true"
-                               $this->_server['login_url'] .= '&renew=true';
-                       } elseif ($gateway) {
-                               // It is recommended that when the "gateway" parameter is set, its value be "true"
-                               $this->_server['login_url'] .= '&gateway=true';
-                       }
-               }
-               phpCAS::traceEnd($this->_server['login_url']);
-               return $this->_server['login_url'];
-       } 
-       
-       /**
-        * This method sets the login URL of the CAS server.
-        * @param $url the login URL
-        * @private
-        * @since 0.4.21 by Wyman Chan
-        */
-       function setServerLoginURL($url)
-               {
-               return $this->_server['login_url'] = $url;
-               }
-       
-       
-       /**
-        * This method sets the serviceValidate URL of the CAS server.
-        * @param $url the serviceValidate URL
-        * @private
-        * @since 1.1.0 by Joachim Fritschi
-        */
-       function setServerServiceValidateURL($url)
-               {
-               return $this->_server['service_validate_url'] = $url;
-               }
-       
-       
-       /**
-        * This method sets the proxyValidate URL of the CAS server.
-        * @param $url the proxyValidate URL
-        * @private
-        * @since 1.1.0 by Joachim Fritschi
-        */
-       function setServerProxyValidateURL($url)
-               {
-               return $this->_server['proxy_validate_url'] = $url;
-               }
-       
-       
-       /**
-        * This method sets the samlValidate URL of the CAS server.
-        * @param $url the samlValidate URL
-        * @private
-        * @since 1.1.0 by Joachim Fritschi
-        */
-       function setServerSamlValidateURL($url)
-               {
-               return $this->_server['saml_validate_url'] = $url;
-               }
-       
-       
-       /**
-        * This method is used to retrieve the service validating URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerServiceValidateURL()
-               { 
-               // the URL is build only when needed
-               if ( empty($this->_server['service_validate_url']) ) {
-                       switch ($this->getServerVersion()) {
-                               case CAS_VERSION_1_0:
-                                       $this->_server['service_validate_url'] = $this->getServerBaseURL().'validate';
-                                       break;
-                               case CAS_VERSION_2_0:
-                                       $this->_server['service_validate_url'] = $this->getServerBaseURL().'serviceValidate';
-                                       break;
-                       }
-               }
-               //      return $this->_server['service_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
-               return $this->_server['service_validate_url'].'?service='.urlencode($this->getURL()); 
-               }
-       /**
-        * This method is used to retrieve the SAML validating URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerSamlValidateURL()
-               {
-               phpCAS::traceBegin();
-               // the URL is build only when needed
-               if ( empty($this->_server['saml_validate_url']) ) {
-                       switch ($this->getServerVersion()) {
-                               case SAML_VERSION_1_1:
-                                       $this->_server['saml_validate_url'] = $this->getServerBaseURL().'samlValidate';
-                                       break;
-                       }
-               }
-               phpCAS::traceEnd($this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL()));
-               return $this->_server['saml_validate_url'].'?TARGET='.urlencode($this->getURL());
-               }
-       /**
-        * This method is used to retrieve the proxy validating URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerProxyValidateURL()
-               { 
-               // the URL is build only when needed
-               if ( empty($this->_server['proxy_validate_url']) ) {
-                       switch ($this->getServerVersion()) {
-                               case CAS_VERSION_1_0:
-                                       $this->_server['proxy_validate_url'] = '';
-                                       break;
-                               case CAS_VERSION_2_0:
-                                       $this->_server['proxy_validate_url'] = $this->getServerBaseURL().'proxyValidate';
-                                       break;
-                       }
-               }
-               //      return $this->_server['proxy_validate_url'].'?service='.preg_replace('/&/','%26',$this->getURL()); 
-               return $this->_server['proxy_validate_url'].'?service='.urlencode($this->getURL()); 
-               }
-       
-       /**
-        * This method is used to retrieve the proxy URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerProxyURL()
-               { 
-               // the URL is build only when needed
-               if ( empty($this->_server['proxy_url']) ) {
-                       switch ($this->getServerVersion()) {
-                               case CAS_VERSION_1_0:
-                                       $this->_server['proxy_url'] = '';
-                                       break;
-                               case CAS_VERSION_2_0:
-                                       $this->_server['proxy_url'] = $this->getServerBaseURL().'proxy';
-                                       break;
-                       }
-               }
-               return $this->_server['proxy_url']; 
-               }
-       
-       /**
-        * This method is used to retrieve the logout URL of the CAS server.
-        * @return a URL.
-        * @private
-        */
-       function getServerLogoutURL()
-               { 
-               // the URL is build only when needed
-               if ( empty($this->_server['logout_url']) ) {
-                       $this->_server['logout_url'] = $this->getServerBaseURL().'logout';
-               }
-               return $this->_server['logout_url']; 
-               }
-       
-       /**
-        * This method sets the logout URL of the CAS server.
-        * @param $url the logout URL
-        * @private
-        * @since 0.4.21 by Wyman Chan
-        */
-       function setServerLogoutURL($url)
-               {
-               return $this->_server['logout_url'] = $url;
-               }
-       
-       /**
-        * An array to store extra curl options.
-        */     
-       var $_curl_options = array();
-       
-       /**
-        * This method is used to set additional user curl options.
-        */
-       function setExtraCurlOption($key, $value)
-               {
-               $this->_curl_options[$key] = $value;
-               }
-       
-       /**
-        * This method checks to see if the request is secured via HTTPS
-        * @return true if https, false otherwise
-        * @private
-        */
-       function isHttps() {
-               //if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) ) {
-               //0.4.24 by Hinnack
-               if ( isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
-       // ########################################################################
-       //  CONSTRUCTOR
-       // ########################################################################
-       /**
-        * CASClient constructor.
-        *
-        * @param $server_version the version of the CAS server
-        * @param $proxy TRUE if the CAS client is a CAS proxy, FALSE otherwise
-        * @param $server_hostname the hostname of the CAS server
-        * @param $server_port the port the CAS server is running on
-        * @param $server_uri the URI the CAS server is responding on
-        * @param $start_session Have phpCAS start PHP sessions (default true)
-        *
-        * @return a newly created CASClient object
-        *
-        * @public
-        */
-       function CASClient(
-                                          $server_version,
-                                          $proxy,
-                                          $server_hostname,
-                                          $server_port,
-                                          $server_uri,
-                                          $start_session = true) {
-               
-               phpCAS::traceBegin();
-               
-               // the redirect header() call and DOM parsing code from domxml-php4-php5.php won't work in PHP4 compatibility mode
-               if (version_compare(PHP_VERSION,'5','>=') && ini_get('zend.ze1_compatibility_mode')) {
-                       phpCAS::error('phpCAS cannot support zend.ze1_compatibility_mode. Sorry.');
-               }
-               $this->_start_session = $start_session;
-
-               if ($this->_start_session && session_id() !== "")
-               {
-                       phpCAS :: error("Another session was started before phpcas. Either disable the session" .
-                               " handling for phpcas in the client() call or modify your application to leave" .
-                               " session handling to phpcas");                 
-               }
-               // skip Session Handling for logout requests and if don't want it'
-               if ($start_session && !$this->isLogoutRequest())
-               {
-                       phpCAS :: trace("Starting a new session");
-                       session_start();
-               }
-               
-               
-               // are we in proxy mode ?
-               $this->_proxy = $proxy;
-               
-               //check version
-               switch ($server_version) {
-                       case CAS_VERSION_1_0:
-                               if ( $this->isProxy() )
-                                       phpCAS::error('CAS proxies are not supported in CAS '
-                                               .$server_version);
-                               break;
-                       case CAS_VERSION_2_0:
-                               break;
-                       case SAML_VERSION_1_1:
-                               break;
-                       default:
-                               phpCAS::error('this version of CAS (`'
-                                       .$server_version
-                                       .'\') is not supported by phpCAS '
-                                       .phpCAS::getVersion());
-               }
-               $this->_server['version'] = $server_version;
-               
-               // check hostname
-               if ( empty($server_hostname) 
-                               || !preg_match('/[\.\d\-abcdefghijklmnopqrstuvwxyz]*/',$server_hostname) ) {
-                       phpCAS::error('bad CAS server hostname (`'.$server_hostname.'\')');
-               }
-               $this->_server['hostname'] = $server_hostname;
-               
-               // check port
-               if ( $server_port == 0 
-                       || !is_int($server_port) ) {
-                       phpCAS::error('bad CAS server port (`'.$server_hostname.'\')');
-               }
-               $this->_server['port'] = $server_port;
-               
-               // check URI
-               if ( !preg_match('/[\.\d\-_abcdefghijklmnopqrstuvwxyz\/]*/',$server_uri) ) {
-                       phpCAS::error('bad CAS server URI (`'.$server_uri.'\')');
-               }
-               // add leading and trailing `/' and remove doubles      
-               $server_uri = preg_replace('/\/\//','/','/'.$server_uri.'/');
-               $this->_server['uri'] = $server_uri;
-               
-               // set to callback mode if PgtIou and PgtId CGI GET parameters are provided 
-               if ( $this->isProxy() ) {
-                       $this->setCallbackMode(!empty($_GET['pgtIou'])&&!empty($_GET['pgtId']));
-               }
-               
-               if ( $this->isCallbackMode() ) {
-                       //callback mode: check that phpCAS is secured
-                       if ( !$this->isHttps() ) {
-                               phpCAS::error('CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server');
-                       }
-               } else {
-                       //normal mode: get ticket and remove it from CGI parameters for developpers
-                       $ticket = (isset($_GET['ticket']) ? $_GET['ticket'] : null);
-                       switch ($this->getServerVersion()) {
-                               case CAS_VERSION_1_0: // check for a Service Ticket
-                                       if( preg_match('/^ST-/',$ticket) ) {
-                                               phpCAS::trace('ST \''.$ticket.'\' found');
-                                               //ST present
-                                               $this->setST($ticket);
-                                               //ticket has been taken into account, unset it to hide it to applications
-                                               unset($_GET['ticket']);
-                                       } else if ( !empty($ticket) ) {
-                                               //ill-formed ticket, halt
-                                               phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
-                                       }
-                                       break;
-                               case CAS_VERSION_2_0: // check for a Service or Proxy Ticket
-                                       if( preg_match('/^[SP]T-/',$ticket) ) {
-                                               phpCAS::trace('ST or PT \''.$ticket.'\' found');
-                                               $this->setPT($ticket);
-                                               unset($_GET['ticket']);
-                                       } else if ( !empty($ticket) ) {
-                                               //ill-formed ticket, halt
-                                               phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
-                                       } 
-                                       break;
-                               case SAML_VERSION_1_1: // SAML just does Service Tickets
-                                       if( preg_match('/^[SP]T-/',$ticket) ) {
-                                               phpCAS::trace('SA \''.$ticket.'\' found');
-                                               $this->setSA($ticket);
-                                               unset($_GET['ticket']);
-                                       } else if ( !empty($ticket) ) {
-                                               //ill-formed ticket, halt
-                                               phpCAS::error('ill-formed ticket found in the URL (ticket=`'.htmlentities($ticket).'\')');
-                                       }
-                                       break;
-                       }
-               }
-               phpCAS::traceEnd();
-       }
-       
-       /** @} */
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                           Session Handling                         XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-
-       /**
-       * A variable to whether phpcas will use its own session handling. Default = true
-       * @hideinitializer
-       * @private
-       */
-       var $_start_session = true;
-
-       function setStartSession($session)
-       {
-               $this->_start_session = session;
-       }
-
-       function getStartSession($session)
-       {
-               $this->_start_session = session;
-       }
-
-               /**
-        * Renaming the session 
-        */
-       function renameSession($ticket)
-       {
-               phpCAS::traceBegin();
-               if($this->_start_session){
-                       if (!empty ($this->_user))
-                       {
-                               $old_session = $_SESSION;
-                               session_destroy();
-                               // set up a new session, of name based on the ticket
-                               $session_id = preg_replace('/[^\w]/', '', $ticket);
-                               phpCAS :: trace("Session ID: ".$session_id);
-                               session_id($session_id);
-                               session_start();
-                               phpCAS :: trace("Restoring old session vars");
-                               $_SESSION = $old_session;
-                       } else
-                       {
-                               phpCAS :: error('Session should only be renamed after successfull authentication');
-                       }
-               }else{
-                       phpCAS :: trace("Skipping session rename since phpCAS is not handling the session.");                   
-               }
-               phpCAS::traceEnd();             
-       }       
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                           AUTHENTICATION                           XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       /**
-        * @addtogroup internalAuthentication
-        * @{
-        */  
-       
-       /**
-        * The Authenticated user. Written by CASClient::setUser(), read by CASClient::getUser().
-        * @attention client applications should use phpCAS::getUser().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_user = '';
-       
-       /**
-        * This method sets the CAS user's login name.
-        *
-        * @param $user the login name of the authenticated user.
-        *
-        * @private
-        */
-       function setUser($user)
-               {
-               $this->_user = $user;
-               }
-       
-       /**
-        * This method returns the CAS user's login name.
-        * @warning should be called only after CASClient::forceAuthentication() or 
-        * CASClient::isAuthenticated(), otherwise halt with an error.
-        *
-        * @return the login name of the authenticated user
-        */
-       function getUser()
-               {
-               if ( empty($this->_user) ) {
-                       phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
-               }
-               return $this->_user;
-               }
-       
-       
-       
-       /***********************************************************************************************************************
-        * Atrributes section
-        * 
-        * @author Matthias Crauwels <matthias.crauwels@ugent.be>, Ghent University, Belgium
-        * 
-        ***********************************************************************************************************************/
-       /**
-        * The Authenticated users attributes. Written by CASClient::setAttributes(), read by CASClient::getAttributes().
-        * @attention client applications should use phpCAS::getAttributes().
-        *
-        * @hideinitializer
-        * @private
-        */     
-       var $_attributes = array();
-       
-       function setAttributes($attributes)     
-               { $this->_attributes = $attributes; }
-       
-       function getAttributes() {
-               if ( empty($this->_user) ) { // if no user is set, there shouldn't be any attributes also...
-                       phpCAS::error('this method should be used only after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()');
-               }
-               return $this->_attributes;
-       }
-       
-       function hasAttributes()
-               { return !empty($this->_attributes); }
-       
-       function hasAttribute($key)
-               { return (is_array($this->_attributes) && array_key_exists($key, $this->_attributes)); }
-       
-       function getAttribute($key)     {
-               if($this->hasAttribute($key)) {
-                       return $this->_attributes[$key];
-               }
-       }
-       
-       /**
-        * This method is called to renew the authentication of the user
-        * If the user is authenticated, renew the connection
-        * If not, redirect to CAS
-        * @public
-        */
-       function renewAuthentication(){
-               phpCAS::traceBegin();
-               // Either way, the user is authenticated by CAS
-               if( isset( $_SESSION['phpCAS']['auth_checked'] ) )
-                       unset($_SESSION['phpCAS']['auth_checked']);
-               if ( $this->isAuthenticated() ) {
-                       phpCAS::trace('user already authenticated; renew');
-                       $this->redirectToCas(false,true);
-               } else {
-                       $this->redirectToCas();
-               }
-               phpCAS::traceEnd();
-       }
-       
-       /**
-        * This method is called to be sure that the user is authenticated. When not 
-        * authenticated, halt by redirecting to the CAS server; otherwise return TRUE.
-        * @return TRUE when the user is authenticated; otherwise halt.
-        * @public
-        */
-       function forceAuthentication()
-               {
-               phpCAS::traceBegin();
-               
-               if ( $this->isAuthenticated() ) {
-                       // the user is authenticated, nothing to be done.
-                       phpCAS::trace('no need to authenticate');
-                       $res = TRUE;
-               } else {
-                       // the user is not authenticated, redirect to the CAS server
-                       if (isset($_SESSION['phpCAS']['auth_checked'])) {
-                               unset($_SESSION['phpCAS']['auth_checked']);
-                       }
-                       $this->redirectToCas(FALSE/* no gateway */);    
-                       // never reached
-                       $res = FALSE;
-               }
-               phpCAS::traceEnd($res);
-               return $res;
-               }
-       
-       /**
-        * An integer that gives the number of times authentication will be cached before rechecked.
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_cache_times_for_auth_recheck = 0;
-       
-       /**
-        * Set the number of times authentication will be cached before rechecked.
-        *
-        * @param $n an integer.
-        *
-        * @public
-        */
-       function setCacheTimesForAuthRecheck($n)
-               {
-               $this->_cache_times_for_auth_recheck = $n;
-               }
-       
-       /**
-        * This method is called to check whether the user is authenticated or not.
-        * @return TRUE when the user is authenticated, FALSE otherwise.
-        * @public
-        */
-       function checkAuthentication()
-               {
-               phpCAS::traceBegin();
-               
-               if ( $this->isAuthenticated() ) {
-                       phpCAS::trace('user is authenticated');
-                       $res = TRUE;
-               } else if (isset($_SESSION['phpCAS']['auth_checked'])) {
-                       // the previous request has redirected the client to the CAS server with gateway=true
-                       unset($_SESSION['phpCAS']['auth_checked']);
-                       $res = FALSE;
-               } else {
-                       //        $_SESSION['phpCAS']['auth_checked'] = true;
-                       //          $this->redirectToCas(TRUE/* gateway */);    
-                       //          // never reached
-                       //          $res = FALSE;
-                       // avoid a check against CAS on every request
-                       if (! isset($_SESSION['phpCAS']['unauth_count']) )
-                               $_SESSION['phpCAS']['unauth_count'] = -2; // uninitialized
-                       
-                       if (($_SESSION['phpCAS']['unauth_count'] != -2 && $this->_cache_times_for_auth_recheck == -1) 
-                                       || ($_SESSION['phpCAS']['unauth_count'] >= 0 && $_SESSION['phpCAS']['unauth_count'] < $this->_cache_times_for_auth_recheck))
-                       {
-                               $res = FALSE;
-                               
-                               if ($this->_cache_times_for_auth_recheck != -1)
-                               {
-                                       $_SESSION['phpCAS']['unauth_count']++;
-                                       phpCAS::trace('user is not authenticated (cached for '.$_SESSION['phpCAS']['unauth_count'].' times of '.$this->_cache_times_for_auth_recheck.')');
-                               }
-                               else
-                               {
-                                       phpCAS::trace('user is not authenticated (cached for until login pressed)');
-                               }
-                       }
-                       else
-                       {
-                               $_SESSION['phpCAS']['unauth_count'] = 0;
-                               $_SESSION['phpCAS']['auth_checked'] = true;
-                               phpCAS::trace('user is not authenticated (cache reset)');
-                               $this->redirectToCas(TRUE/* gateway */);        
-                               // never reached
-                               $res = FALSE;
-                       }
-               }
-               phpCAS::traceEnd($res);
-               return $res;
-               }
-       
-       /**
-        * This method is called to check if the user is authenticated (previously or by
-        * tickets given in the URL).
-        *
-        * @return TRUE when the user is authenticated. Also may redirect to the same URL without the ticket.
-        *
-        * @public
-        */
-       function isAuthenticated()
-               {
-               phpCAS::traceBegin();
-               $res = FALSE;
-               $validate_url = '';
-               
-               if ( $this->wasPreviouslyAuthenticated() ) {
-                       if($this->hasST() || $this->hasPT() || $this->hasSA()){
-                               // User has a additional ticket but was already authenticated
-                               phpCAS::trace('ticket was present and will be discarded, use renewAuthenticate()');
-                               header('Location: '.$this->getURL());
-                               phpCAS::log( "Prepare redirect to remove ticket: ".$this->getURL() );
-                               phpCAS::traceExit();
-                               exit();
-                       }else{
-                               // the user has already (previously during the session) been
-                               // authenticated, nothing to be done.
-                               phpCAS::trace('user was already authenticated, no need to look for tickets');
-                               $res = TRUE;
-                       }
-               }
-               else {
-                       if ( $this->hasST() ) {
-                               // if a Service Ticket was given, validate it
-                               phpCAS::trace('ST `'.$this->getST().'\' is present');
-                               $this->validateST($validate_url,$text_response,$tree_response); // if it fails, it halts
-                               phpCAS::trace('ST `'.$this->getST().'\' was validated');
-                               if ( $this->isProxy() ) {
-                                       $this->validatePGT($validate_url,$text_response,$tree_response); // idem
-                                       phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
-                                       $_SESSION['phpCAS']['pgt'] = $this->getPGT();
-                               }
-                               $_SESSION['phpCAS']['user'] = $this->getUser();
-                               $res = TRUE;
-                       }
-                       elseif ( $this->hasPT() ) {
-                               // if a Proxy Ticket was given, validate it
-                               phpCAS::trace('PT `'.$this->getPT().'\' is present');
-                               $this->validatePT($validate_url,$text_response,$tree_response); // note: if it fails, it halts
-                               phpCAS::trace('PT `'.$this->getPT().'\' was validated');
-                               if ( $this->isProxy() ) {
-                                       $this->validatePGT($validate_url,$text_response,$tree_response); // idem
-                                       phpCAS::trace('PGT `'.$this->getPGT().'\' was validated');
-                                       $_SESSION['phpCAS']['pgt'] = $this->getPGT();
-                               }
-                               $_SESSION['phpCAS']['user'] = $this->getUser();
-                               $res = TRUE;
-                       }
-                       elseif ( $this->hasSA() ) {
-                               // if we have a SAML ticket, validate it.
-                               phpCAS::trace('SA `'.$this->getSA().'\' is present');
-                               $this->validateSA($validate_url,$text_response,$tree_response); // if it fails, it halts
-                               phpCAS::trace('SA `'.$this->getSA().'\' was validated');
-                               $_SESSION['phpCAS']['user'] = $this->getUser();
-                               $_SESSION['phpCAS']['attributes'] = $this->getAttributes();
-                               $res = TRUE;
-                       }
-                       else {
-                               // no ticket given, not authenticated
-                               phpCAS::trace('no ticket found');
-                       }
-                       if ($res) {
-                               // if called with a ticket parameter, we need to redirect to the app without the ticket so that CAS-ification is transparent to the browser (for later POSTS)
-                               // most of the checks and errors should have been made now, so we're safe for redirect without masking error messages.
-                               // remove the ticket as a security precaution to prevent a ticket in the HTTP_REFERRER
-                               header('Location: '.$this->getURL());
-                               phpCAS::log( "Prepare redirect to : ".$this->getURL() );
-                               phpCAS::traceExit();
-                               exit();
-                       }
-               }
-               
-               phpCAS::traceEnd($res);
-               return $res;
-               }
-       
-       /**
-        * This method tells if the current session is authenticated.
-        * @return true if authenticated based soley on $_SESSION variable
-        * @since 0.4.22 by Brendan Arnold
-        */
-       function isSessionAuthenticated ()
-               {
-               return !empty($_SESSION['phpCAS']['user']);
-               }
-       
-       /**
-        * This method tells if the user has already been (previously) authenticated
-        * by looking into the session variables.
-        *
-        * @note This function switches to callback mode when needed.
-        *
-        * @return TRUE when the user has already been authenticated; FALSE otherwise.
-        *
-        * @private
-        */
-       function wasPreviouslyAuthenticated()
-               {
-               phpCAS::traceBegin();
-               
-               if ( $this->isCallbackMode() ) {
-                       $this->callback();
-               }
-               
-               $auth = FALSE;
-               
-               if ( $this->isProxy() ) {
-                       // CAS proxy: username and PGT must be present
-                       if ( $this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
-                               // authentication already done
-                               $this->setUser($_SESSION['phpCAS']['user']);
-                               $this->setPGT($_SESSION['phpCAS']['pgt']);
-                               phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\', PGT = `'.$_SESSION['phpCAS']['pgt'].'\''); 
-                               $auth = TRUE;
-                       } elseif ( $this->isSessionAuthenticated() && empty($_SESSION['phpCAS']['pgt']) ) {
-                               // these two variables should be empty or not empty at the same time
-                               phpCAS::trace('username found (`'.$_SESSION['phpCAS']['user'].'\') but PGT is empty');
-                               // unset all tickets to enforce authentication
-                               unset($_SESSION['phpCAS']);
-                               $this->setST('');
-                               $this->setPT('');
-                       } elseif ( !$this->isSessionAuthenticated() && !empty($_SESSION['phpCAS']['pgt']) ) {
-                               // these two variables should be empty or not empty at the same time
-                               phpCAS::trace('PGT found (`'.$_SESSION['phpCAS']['pgt'].'\') but username is empty'); 
-                               // unset all tickets to enforce authentication
-                               unset($_SESSION['phpCAS']);
-                               $this->setST('');
-                               $this->setPT('');
-                       } else {
-                               phpCAS::trace('neither user not PGT found'); 
-                       }
-               } else {
-                       // `simple' CAS client (not a proxy): username must be present
-                       if ( $this->isSessionAuthenticated() ) {
-                               // authentication already done
-                               $this->setUser($_SESSION['phpCAS']['user']);
-                               if(isset($_SESSION['phpCAS']['attributes'])){
-                                       $this->setAttributes($_SESSION['phpCAS']['attributes']);
-                               }
-                               phpCAS::trace('user = `'.$_SESSION['phpCAS']['user'].'\''); 
-                               $auth = TRUE;
-                       } else {
-                               phpCAS::trace('no user found');
-                       }
-               }
-               
-               phpCAS::traceEnd($auth);
-               return $auth;
-               }
-       
-       /**
-        * This method is used to redirect the client to the CAS server.
-        * It is used by CASClient::forceAuthentication() and CASClient::checkAuthentication().
-        * @param $gateway true to check authentication, false to force it
-        * @param $renew true to force the authentication with the CAS server
-        * @public
-        */
-       function redirectToCas($gateway=false,$renew=false){
-               phpCAS::traceBegin();
-               $cas_url = $this->getServerLoginURL($gateway,$renew);
-               header('Location: '.$cas_url);
-               phpCAS::log( "Redirect to : ".$cas_url );
-               
-               $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_WANTED));
-               
-               printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
-               $this->printHTMLFooter();
-               
-               phpCAS::traceExit();
-               exit();
-       }
-       
-       
-       /**
-        * This method is used to logout from CAS.
-        * @params $params an array that contains the optional url and service parameters that will be passed to the CAS server
-        * @public
-        */
-       function logout($params) {
-               phpCAS::traceBegin();
-               $cas_url = $this->getServerLogoutURL();
-               $paramSeparator = '?';
-               if (isset($params['url'])) {
-                       $cas_url = $cas_url . $paramSeparator . "url=" . urlencode($params['url']); 
-                       $paramSeparator = '&';
-               }
-               if (isset($params['service'])) {
-                       $cas_url = $cas_url . $paramSeparator . "service=" . urlencode($params['service']); 
-               }
-               header('Location: '.$cas_url);
-               phpCAS::log( "Prepare redirect to : ".$cas_url );
-               
-               session_unset();
-               session_destroy();
-               
-               $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT));
-               printf('<p>'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'</p>',$cas_url);
-               $this->printHTMLFooter();
-               
-               phpCAS::traceExit();
-               exit();
-       }
-       
-       /**
-        * @return true if the current request is a logout request.
-        * @private
-        */
-       function isLogoutRequest() {
-               return !empty($_POST['logoutRequest']);
-       }
-       
-       /**
-        * @return true if a logout request is allowed.
-        * @private
-        */
-       function isLogoutRequestAllowed() {
-       }
-       
-       /**
-        * This method handles logout requests.
-        * @param $check_client true to check the client bofore handling the request, 
-        * false not to perform any access control. True by default.
-        * @param $allowed_clients an array of host names allowed to send logout requests. 
-        * By default, only the CAs server (declared in the constructor) will be allowed.
-        * @public
-        */
-       function handleLogoutRequests($check_client=true, $allowed_clients=false) {
-               phpCAS::traceBegin();
-               if (!$this->isLogoutRequest()) {
-                       phpCAS::log("Not a logout request");
-                       phpCAS::traceEnd();
-                       return;
-               }
-               if(!$this->_start_session){
-                       phpCAS::log("phpCAS can't handle logout requests if it does not manage the session.");
-               }
-               phpCAS::log("Logout requested");
-               phpCAS::log("SAML REQUEST: ".$_POST['logoutRequest']);
-               if ($check_client) {
-                       if (!$allowed_clients) {
-                               $allowed_clients = array( $this->getServerHostname() ); 
-                       }
-                       $client_ip = $_SERVER['REMOTE_ADDR'];
-                       $client = gethostbyaddr($client_ip);
-                       phpCAS::log("Client: ".$client."/".$client_ip); 
-                       $allowed = false;
-                       foreach ($allowed_clients as $allowed_client) {
-                               if (($client == $allowed_client) or ($client_ip == $allowed_client)) { 
-                                       phpCAS::log("Allowed client '".$allowed_client."' matches, logout request is allowed");
-                                       $allowed = true;
-                                       break;
-                               } else {
-                                       phpCAS::log("Allowed client '".$allowed_client."' does not match");
-                               }
-                       }
-                       if (!$allowed) {
-                               phpCAS::error("Unauthorized logout request from client '".$client."'");
-                               printf("Unauthorized!");
-                               phpCAS::traceExit();
-                               exit();
-                       }
-               } else {
-                       phpCAS::log("No access control set");
-               }
-               // Extract the ticket from the SAML Request
-               preg_match("|<samlp:SessionIndex>(.*)</samlp:SessionIndex>|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3);
-               $wrappedSamlSessionIndex = preg_replace('|<samlp:SessionIndex>|','',$tick[0][0]);
-               $ticket2logout = preg_replace('|</samlp:SessionIndex>|','',$wrappedSamlSessionIndex);
-               phpCAS::log("Ticket to logout: ".$ticket2logout);
-               $session_id = preg_replace('/[^\w]/','',$ticket2logout);
-               phpCAS::log("Session id: ".$session_id);
-               
-               // destroy a possible application session created before phpcas
-               if(session_id()  !== ""){
-                       session_unset();
-                       session_destroy();
-               }
-               // fix session ID
-               session_id($session_id);
-               $_COOKIE[session_name()]=$session_id;
-               $_GET[session_name()]=$session_id;
-               
-               // Overwrite session
-               session_start();        
-               session_unset();
-               session_destroy();
-               printf("Disconnected!");
-               phpCAS::traceExit();
-               exit();
-       }
-       
-       /** @} */
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                  BASIC CLIENT FEATURES (CAS 1.0)                   XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       // ########################################################################
-       //  ST
-       // ########################################################################
-       /**
-        * @addtogroup internalBasic
-        * @{
-        */  
-       
-       /**
-        * the Service Ticket provided in the URL of the request if present
-        * (empty otherwise). Written by CASClient::CASClient(), read by 
-        * CASClient::getST() and CASClient::hasPGT().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_st = '';
-       
-       /**
-        * This method returns the Service Ticket provided in the URL of the request.
-        * @return The service ticket.
-        * @private
-        */
-       function getST()
-               { return $this->_st; }
-       
-       /**
-        * This method stores the Service Ticket.
-        * @param $st The Service Ticket.
-        * @private
-        */
-       function setST($st)
-               { $this->_st = $st; }
-       
-       /**
-        * This method tells if a Service Ticket was stored.
-        * @return TRUE if a Service Ticket has been stored.
-        * @private
-        */
-       function hasST()
-               { return !empty($this->_st); }
-       
-       /** @} */
-       
-       // ########################################################################
-       //  ST VALIDATION
-       // ########################################################################
-       /**
-        * @addtogroup internalBasic
-        * @{
-        */  
-       
-       /**
-        * the certificate of the CAS server.
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_cas_server_cert = '';
-       
-       /**
-        * the certificate of the CAS server CA.
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_cas_server_ca_cert = '';
-       
-       /**
-        * Set to true not to validate the CAS server.
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_no_cas_server_validation = false;
-       
-       /**
-        * Set the certificate of the CAS server.
-        *
-        * @param $cert the PEM certificate
-        */
-       function setCasServerCert($cert)
-               {
-               $this->_cas_server_cert = $cert;
-               }
-       
-       /**
-        * Set the CA certificate of the CAS server.
-        *
-        * @param $cert the PEM certificate of the CA that emited the cert of the server
-        */
-       function setCasServerCACert($cert)
-               {
-               $this->_cas_server_ca_cert = $cert;
-               }
-       
-       /**
-        * Set no SSL validation for the CAS server.
-        */
-       function setNoCasServerValidation()
-               {
-               $this->_no_cas_server_validation = true;
-               }
-       
-       /**
-        * This method is used to validate a ST; halt on failure, and sets $validate_url,
-        * $text_reponse and $tree_response on success. These parameters are used later
-        * by CASClient::validatePGT() for CAS proxies.
-        * Used for all CAS 1.0 validations
-        * @param $validate_url the URL of the request to the CAS server.
-        * @param $text_response the response of the CAS server, as is (XML text).
-        * @param $tree_response the response of the CAS server, as a DOM XML tree.
-        *
-        * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
-        *
-        * @private
-        */
-       function validateST($validate_url,&$text_response,&$tree_response)
-               {
-               phpCAS::traceBegin();
-               // build the URL to validate the ticket
-               $validate_url = $this->getServerServiceValidateURL().'&ticket='.$this->getST();
-               if ( $this->isProxy() ) {
-                       // pass the callback url for CAS proxies
-                       $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
-               }
-               
-               // open and read the URL
-               if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
-                       phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
-                       $this->authError('ST not validated',
-                               $validate_url,
-                               TRUE/*$no_response*/);
-               }
-               
-               // analyze the result depending on the version
-               switch ($this->getServerVersion()) {
-                       case CAS_VERSION_1_0:
-                               if (preg_match('/^no\n/',$text_response)) {
-                                       phpCAS::trace('ST has not been validated');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               FALSE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               if (!preg_match('/^yes\n/',$text_response)) {
-                                       phpCAS::trace('ill-formed response');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // ST has been validated, extract the user name
-                               $arr = preg_split('/\n/',$text_response);
-                               $this->setUser(trim($arr[1]));
-                               break;
-                       case CAS_VERSION_2_0:
-                               // read the response of the CAS server into a DOM object
-                               if ( !($dom = domxml_open_mem($text_response))) {
-                                       phpCAS::trace('domxml_open_mem() failed');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // read the root node of the XML tree
-                               if ( !($tree_response = $dom->document_element()) ) {
-                                       phpCAS::trace('document_element() failed');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // insure that tag name is 'serviceResponse'
-                               if ( $tree_response->node_name() != 'serviceResponse' ) {
-                                       phpCAS::trace('bad XML root node (should be `serviceResponse\' instead of `'.$tree_response->node_name().'\'');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
-                                       // authentication succeded, extract the user name
-                                       if ( sizeof($user_elements = $success_elements[0]->get_elements_by_tagname("user")) == 0) {
-                                               phpCAS::trace('<authenticationSuccess> found, but no <user>');
-                                               $this->authError('ST not validated',
-                                                       $validate_url,
-                                                       FALSE/*$no_response*/,
-                                                       TRUE/*$bad_response*/,
-                                                       $text_response);
-                                       }
-                                       $user = trim($user_elements[0]->get_content());
-                                       phpCAS::trace('user = `'.$user);
-                                       $this->setUser($user);
-                                       
-                               } else if ( sizeof($failure_elements = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
-                                       phpCAS::trace('<authenticationFailure> found');
-                                       // authentication failed, extract the error code and message
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               FALSE/*$bad_response*/,
-                                               $text_response,
-                                               $failure_elements[0]->get_attribute('code')/*$err_code*/,
-                                               trim($failure_elements[0]->get_content())/*$err_msg*/);
-                               } else {
-                                       phpCAS::trace('neither <authenticationSuccess> nor <authenticationFailure> found');
-                                       $this->authError('ST not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               break;
-               }
-               $this->renameSession($this->getST());
-               // at this step, ST has been validated and $this->_user has been set,
-               phpCAS::traceEnd(TRUE);
-               return TRUE;
-               }
-       
-       // ########################################################################
-       //  SAML VALIDATION
-       // ########################################################################
-       /**
-        * @addtogroup internalBasic
-        * @{
-        */
-       
-       /**
-        * This method is used to validate a SAML TICKET; halt on failure, and sets $validate_url,
-        * $text_reponse and $tree_response on success. These parameters are used later
-        * by CASClient::validatePGT() for CAS proxies.
-        *
-        * @param $validate_url the URL of the request to the CAS server.
-        * @param $text_response the response of the CAS server, as is (XML text).
-        * @param $tree_response the response of the CAS server, as a DOM XML tree.
-        *
-        * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
-        *
-        * @private
-        */
-       function validateSA($validate_url,&$text_response,&$tree_response)
-               {
-               phpCAS::traceBegin();
-               
-               // build the URL to validate the ticket
-               $validate_url = $this->getServerSamlValidateURL();
-               
-               // open and read the URL
-               if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
-                       phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
-                       $this->authError('SA not validated', $validate_url, TRUE/*$no_response*/);
-               }
-               
-               phpCAS::trace('server version: '.$this->getServerVersion());
-               
-               // analyze the result depending on the version
-               switch ($this->getServerVersion()) {
-                       case SAML_VERSION_1_1:
-                               
-                               // read the response of the CAS server into a DOM object
-                               if ( !($dom = domxml_open_mem($text_response))) {
-                                       phpCAS::trace('domxml_open_mem() failed');
-                                       $this->authError('SA not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // read the root node of the XML tree
-                               if ( !($tree_response = $dom->document_element()) ) {
-                                       phpCAS::trace('document_element() failed');
-                                       $this->authError('SA not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // insure that tag name is 'Envelope'
-                               if ( $tree_response->node_name() != 'Envelope' ) {
-                                       phpCAS::trace('bad XML root node (should be `Envelope\' instead of `'.$tree_response->node_name().'\'');
-                                       $this->authError('SA not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               // check for the NameIdentifier tag in the SAML response
-                               if ( sizeof($success_elements = $tree_response->get_elements_by_tagname("NameIdentifier")) != 0) {
-                                       phpCAS::trace('NameIdentifier found');
-                                       $user = trim($success_elements[0]->get_content());
-                                       phpCAS::trace('user = `'.$user.'`');
-                                       $this->setUser($user);
-                                       $this->setSessionAttributes($text_response);
-                               } else {
-                                       phpCAS::trace('no <NameIdentifier> tag found in SAML payload');
-                                       $this->authError('SA not validated',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               TRUE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               break;
-               }
-               $this->renameSession($this->getSA());
-               // at this step, ST has been validated and $this->_user has been set,
-               phpCAS::traceEnd(TRUE);
-               return TRUE;
-               }
-       
-       /**
-        * This method will parse the DOM and pull out the attributes from the SAML
-        * payload and put them into an array, then put the array into the session.
-        *
-        * @param $text_response the SAML payload.
-        * @return bool TRUE when successfull and FALSE if no attributes a found
-        *
-        * @private
-        */
-       function setSessionAttributes($text_response)
-               {
-               phpCAS::traceBegin();
-               
-               $result = FALSE;
-               
-               if (isset($_SESSION[SAML_ATTRIBUTES])) {
-                       phpCAS::trace("session attrs already set.");  //testbml - do we care?
-               }
-               
-               $attr_array = array();
-               
-               if (($dom = domxml_open_mem($text_response))) {
-                       $xPath = $dom->xpath_new_context();
-                       $xPath->xpath_register_ns('samlp', 'urn:oasis:names:tc:SAML:1.0:protocol');
-                       $xPath->xpath_register_ns('saml', 'urn:oasis:names:tc:SAML:1.0:assertion');
-                       $nodelist = $xPath->xpath_eval("//saml:Attribute");
-                       if($nodelist){
-                               $attrs = $nodelist->nodeset;
-                               foreach($attrs as $attr){
-                                       $xres = $xPath->xpath_eval("saml:AttributeValue", $attr);
-                                       $name = $attr->get_attribute("AttributeName");
-                                       $value_array = array();
-                                       foreach($xres->nodeset as $node){
-                                               $value_array[] = $node->get_content();
-                                       }
-                                       $attr_array[$name] = $value_array;
-                               }
-                               $_SESSION[SAML_ATTRIBUTES] = $attr_array;
-                               // UGent addition...
-                               foreach($attr_array as $attr_key => $attr_value) {
-                                       if(count($attr_value) > 1) {
-                                               $this->_attributes[$attr_key] = $attr_value;
-                                               phpCAS::trace("* " . $attr_key . "=" . $attr_value);
-                                       }
-                                       else {
-                                               $this->_attributes[$attr_key] = $attr_value[0];
-                                               phpCAS::trace("* " . $attr_key . "=" . $attr_value[0]);
-                                       }
-                               }
-                               $result = TRUE;
-                       }else{
-                               phpCAS::trace("SAML Attributes are empty");
-                               $result = FALSE;
-                       }
-               }
-               phpCAS::traceEnd($result);
-               return $result;
-               }
-       
-       /** @} */
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                     PROXY FEATURES (CAS 2.0)                       XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       // ########################################################################
-       //  PROXYING
-       // ########################################################################
-       /**
-        * @addtogroup internalProxy
-        * @{
-        */
-       
-       /**
-        * A boolean telling if the client is a CAS proxy or not. Written by CASClient::CASClient(), 
-        * read by CASClient::isProxy().
-        *
-        * @private
-        */
-       var $_proxy;
-       
-       /**
-        * Tells if a CAS client is a CAS proxy or not
-        *
-        * @return TRUE when the CAS client is a CAs proxy, FALSE otherwise
-        *
-        * @private
-        */
-       function isProxy()
-               {
-               return $this->_proxy;
-               }
-       
-       /** @} */
-       // ########################################################################
-       //  PGT
-       // ########################################################################
-       /**
-        * @addtogroup internalProxy
-        * @{
-        */  
-       
-       /**
-        * the Proxy Grnting Ticket given by the CAS server (empty otherwise). 
-        * Written by CASClient::setPGT(), read by CASClient::getPGT() and CASClient::hasPGT().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_pgt = '';
-       
-       /**
-        * This method returns the Proxy Granting Ticket given by the CAS server.
-        * @return The Proxy Granting Ticket.
-        * @private
-        */
-       function getPGT()
-               { return $this->_pgt; }
-       
-       /**
-        * This method stores the Proxy Granting Ticket.
-        * @param $pgt The Proxy Granting Ticket.
-        * @private
-        */
-       function setPGT($pgt)
-               { $this->_pgt = $pgt; }
-       
-       /**
-        * This method tells if a Proxy Granting Ticket was stored.
-        * @return TRUE if a Proxy Granting Ticket has been stored.
-        * @private
-        */
-       function hasPGT()
-               { return !empty($this->_pgt); }
-       
-       /** @} */
-       
-       // ########################################################################
-       //  CALLBACK MODE
-       // ########################################################################
-       /**
-        * @addtogroup internalCallback
-        * @{
-        */  
-       /**
-        * each PHP script using phpCAS in proxy mode is its own callback to get the
-        * PGT back from the CAS server. callback_mode is detected by the constructor
-        * thanks to the GET parameters.
-        */
-       
-       /**
-        * a boolean to know if the CAS client is running in callback mode. Written by
-        * CASClient::setCallBackMode(), read by CASClient::isCallbackMode().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_callback_mode = FALSE;
-       
-       /**
-        * This method sets/unsets callback mode.
-        *
-        * @param $callback_mode TRUE to set callback mode, FALSE otherwise.
-        *
-        * @private
-        */
-       function setCallbackMode($callback_mode)
-               {
-               $this->_callback_mode = $callback_mode;
-               }
-       
-       /**
-        * This method returns TRUE when the CAs client is running i callback mode, 
-        * FALSE otherwise.
-        *
-        * @return A boolean.
-        *
-        * @private
-        */
-       function isCallbackMode()
-               {
-               return $this->_callback_mode;
-               }
-       
-       /**
-        * the URL that should be used for the PGT callback (in fact the URL of the 
-        * current request without any CGI parameter). Written and read by 
-        * CASClient::getCallbackURL().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_callback_url = '';
-       
-       /**
-        * This method returns the URL that should be used for the PGT callback (in
-        * fact the URL of the current request without any CGI parameter, except if
-        * phpCAS::setFixedCallbackURL() was used).
-        *
-        * @return The callback URL
-        *
-        * @private
-        */
-       function getCallbackURL()
-               {
-               // the URL is built when needed only
-               if ( empty($this->_callback_url) ) {
-                       $final_uri = '';
-                       // remove the ticket if present in the URL
-                       $final_uri = 'https://';
-                       /* replaced by Julien Marchal - v0.4.6
-                        * $this->uri .= $_SERVER['SERVER_NAME'];
-                        */
-                       if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
-                               /* replaced by teedog - v0.4.12
-                                * $final_uri .= $_SERVER['SERVER_NAME'];
-                                */
-                               if (empty($_SERVER['SERVER_NAME'])) {
-                                       $final_uri .= $_SERVER['HTTP_HOST'];
-                               } else {
-                                       $final_uri .= $_SERVER['SERVER_NAME'];
-                               }
-                       } else {
-                               $final_uri .= $_SERVER['HTTP_X_FORWARDED_SERVER'];
-                       }
-                       if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
-                                       || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
-                               $final_uri .= ':';
-                               $final_uri .= $_SERVER['SERVER_PORT'];
-                       }
-                       $request_uri = $_SERVER['REQUEST_URI'];
-                       $request_uri = preg_replace('/\?.*$/','',$request_uri);
-                       $final_uri .= $request_uri;
-                       $this->setCallbackURL($final_uri);
-               }
-               return $this->_callback_url;
-               }
-       
-       /**
-        * This method sets the callback url.
-        *
-        * @param $callback_url url to set callback 
-        *
-        * @private
-        */
-       function setCallbackURL($url)
-               {
-               return $this->_callback_url = $url;
-               }
-       
-       /**
-        * This method is called by CASClient::CASClient() when running in callback
-        * mode. It stores the PGT and its PGT Iou, prints its output and halts.
-        *
-        * @private
-        */
-       function callback()
-               {
-               phpCAS::traceBegin();
-               if (preg_match('/PGTIOU-[\.\-\w]/', $_GET['pgtIou'])){
-                       if(preg_match('/[PT]GT-[\.\-\w]/', $_GET['pgtId'])){
-                               $this->printHTMLHeader('phpCAS callback');
-                               $pgt_iou = $_GET['pgtIou'];
-                               $pgt = $_GET['pgtId'];
-                               phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')');
-                               echo '<p>Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').</p>';
-                               $this->storePGT($pgt,$pgt_iou);
-                               $this->printHTMLFooter();
-                       }else{
-                               phpCAS::error('PGT format invalid' . $_GET['pgtId']);
-                       }
-               }else{
-                       phpCAS::error('PGTiou format invalid' . $_GET['pgtIou']);
-               }
-               phpCAS::traceExit();
-               exit();
-               }
-       
-       /** @} */
-       
-       // ########################################################################
-       //  PGT STORAGE
-       // ########################################################################
-       /**
-        * @addtogroup internalPGTStorage
-        * @{
-        */  
-       
-       /**
-        * an instance of a class inheriting of PGTStorage, used to deal with PGT
-        * storage. Created by CASClient::setPGTStorageFile() or CASClient::setPGTStorageDB(), used 
-        * by CASClient::setPGTStorageFile(), CASClient::setPGTStorageDB() and CASClient::initPGTStorage().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_pgt_storage = null;
-       
-       /**
-        * This method is used to initialize the storage of PGT's.
-        * Halts on error.
-        *
-        * @private
-        */
-       function initPGTStorage()
-               {
-               // if no SetPGTStorageXxx() has been used, default to file
-               if ( !is_object($this->_pgt_storage) ) {
-                       $this->setPGTStorageFile();
-               }
-               
-               // initializes the storage
-               $this->_pgt_storage->init();
-               }
-       
-       /**
-        * This method stores a PGT. Halts on error.
-        *
-        * @param $pgt the PGT to store
-        * @param $pgt_iou its corresponding Iou
-        *
-        * @private
-        */
-       function storePGT($pgt,$pgt_iou)
-               {
-               // ensure that storage is initialized
-               $this->initPGTStorage();
-               // writes the PGT
-               $this->_pgt_storage->write($pgt,$pgt_iou);
-               }
-       
-       /**
-        * This method reads a PGT from its Iou and deletes the corresponding storage entry.
-        *
-        * @param $pgt_iou the PGT Iou
-        *
-        * @return The PGT corresponding to the Iou, FALSE when not found.
-        *
-        * @private
-        */
-       function loadPGT($pgt_iou)
-               {
-               // ensure that storage is initialized
-               $this->initPGTStorage();
-               // read the PGT
-               return $this->_pgt_storage->read($pgt_iou);
-               }
-       
-       /**
-        * This method is used to tell phpCAS to store the response of the
-        * CAS server to PGT requests onto the filesystem. 
-        *
-        * @param $format the format used to store the PGT's (`plain' and `xml' allowed)
-        * @param $path the path where the PGT's should be stored
-        *
-        * @public
-        */
-       function setPGTStorageFile($format='',
-               $path='')
-               {
-               // check that the storage has not already been set
-               if ( is_object($this->_pgt_storage) ) {
-                       phpCAS::error('PGT storage already defined');
-               }
-               
-               // create the storage object
-               $this->_pgt_storage = new PGTStorageFile($this,$format,$path);
-               }
-       
-       // ########################################################################
-       //  PGT VALIDATION
-       // ########################################################################
-       /**
-        * This method is used to validate a PGT; halt on failure.
-        * 
-        * @param $validate_url the URL of the request to the CAS server.
-        * @param $text_response the response of the CAS server, as is (XML text); result
-        * of CASClient::validateST() or CASClient::validatePT().
-        * @param $tree_response the response of the CAS server, as a DOM XML tree; result
-        * of CASClient::validateST() or CASClient::validatePT().
-        *
-        * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
-        *
-        * @private
-        */
-       function validatePGT(&$validate_url,$text_response,$tree_response)
-               {
-               // here cannot use phpCAS::traceBegin(); alongside domxml-php4-to-php5.php
-               phpCAS::log('start validatePGT()');
-               if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) {
-                       phpCAS::trace('<proxyGrantingTicket> not found');
-                       // authentication succeded, but no PGT Iou was transmitted
-                       $this->authError('Ticket validated but no PGT Iou transmitted',
-                               $validate_url,
-                               FALSE/*$no_response*/,
-                               FALSE/*$bad_response*/,
-                               $text_response);
-               } else {
-                       // PGT Iou transmitted, extract it
-                       $pgt_iou = trim($arr[0]->get_content());
-                       if(preg_match('/PGTIOU-[\.\-\w]/',$pgt_iou)){ 
-                               $pgt = $this->loadPGT($pgt_iou);
-                               if ( $pgt == FALSE ) {
-                                       phpCAS::trace('could not load PGT');
-                                       $this->authError('PGT Iou was transmitted but PGT could not be retrieved',
-                                               $validate_url,
-                                               FALSE/*$no_response*/,
-                                               FALSE/*$bad_response*/,
-                                               $text_response);
-                               }
-                               $this->setPGT($pgt);
-                       }else{
-                               phpCAS::trace('PGTiou format error');
-                               $this->authError('PGT Iou was transmitted but has wrong fromat',
-                                       $validate_url,
-                                       FALSE/*$no_response*/,
-                                       FALSE/*$bad_response*/,
-                                       $text_response);
-                       }
-                       
-               }
-               // here, cannot use     phpCAS::traceEnd(TRUE); alongside domxml-php4-to-php5.php
-               phpCAS::log('end validatePGT()');
-               return TRUE;
-               }
-       
-       // ########################################################################
-       //  PGT VALIDATION
-       // ########################################################################
-       
-       /**
-        * This method is used to retrieve PT's from the CAS server thanks to a PGT.
-        * 
-        * @param $target_service the service to ask for with the PT.
-        * @param $err_code an error code (PHPCAS_SERVICE_OK on success).
-        * @param $err_msg an error message (empty on success).
-        *
-        * @return a Proxy Ticket, or FALSE on error.
-        *
-        * @private
-        */
-       function retrievePT($target_service,&$err_code,&$err_msg)
-               {
-               phpCAS::traceBegin();
-               
-               // by default, $err_msg is set empty and $pt to TRUE. On error, $pt is
-               // set to false and $err_msg to an error message. At the end, if $pt is FALSE 
-               // and $error_msg is still empty, it is set to 'invalid response' (the most
-               // commonly encountered error).
-               $err_msg = '';
-               
-               // build the URL to retrieve the PT
-               //      $cas_url = $this->getServerProxyURL().'?targetService='.preg_replace('/&/','%26',$target_service).'&pgt='.$this->getPGT();
-               $cas_url = $this->getServerProxyURL().'?targetService='.urlencode($target_service).'&pgt='.$this->getPGT();
-               
-               // open and read the URL
-               if ( !$this->readURL($cas_url,''/*cookies*/,$headers,$cas_response,$err_msg) ) {
-                       phpCAS::trace('could not open URL \''.$cas_url.'\' to validate ('.$err_msg.')');
-                       $err_code = PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE;
-                       $err_msg = 'could not retrieve PT (no response from the CAS server)';
-                       phpCAS::traceEnd(FALSE);
-                       return FALSE;
-               }
-               
-               $bad_response = FALSE;
-               
-               if ( !$bad_response ) {
-                       // read the response of the CAS server into a DOM object
-                       if ( !($dom = @domxml_open_mem($cas_response))) {
-                               phpCAS::trace('domxml_open_mem() failed');
-                               // read failed
-                               $bad_response = TRUE;
-                       } 
-               }
-               
-               if ( !$bad_response ) {
-                       // read the root node of the XML tree
-                       if ( !($root = $dom->document_element()) ) {
-                               phpCAS::trace('document_element() failed');
-                               // read failed
-                               $bad_response = TRUE;
-                       } 
-               }
-               
-               if ( !$bad_response ) {
-                       // insure that tag name is 'serviceResponse'
-                       if ( $root->node_name() != 'serviceResponse' ) {
-                               phpCAS::trace('node_name() failed');
-                               // bad root node
-                               $bad_response = TRUE;
-                       } 
-               }
-               
-               if ( !$bad_response ) {
-                       // look for a proxySuccess tag
-                       if ( sizeof($arr = $root->get_elements_by_tagname("proxySuccess")) != 0) {
-                               // authentication succeded, look for a proxyTicket tag
-                               if ( sizeof($arr = $root->get_elements_by_tagname("proxyTicket")) != 0) {
-                                       $err_code = PHPCAS_SERVICE_OK;
-                                       $err_msg = '';
-                                       phpCAS::trace('original PT: '.trim($arr[0]->get_content()));
-                                       $pt = trim($arr[0]->get_content());
-                                       phpCAS::traceEnd($pt);
-                                       return $pt;
-                               } else {
-                                       phpCAS::trace('<proxySuccess> was found, but not <proxyTicket>');
-                               }
-                       } 
-                       // look for a proxyFailure tag
-                       else if ( sizeof($arr = $root->get_elements_by_tagname("proxyFailure")) != 0) {
-                               // authentication failed, extract the error
-                               $err_code = PHPCAS_SERVICE_PT_FAILURE;
-                               $err_msg = 'PT retrieving failed (code=`'
-                                       .$arr[0]->get_attribute('code')
-                                       .'\', message=`'
-                                       .trim($arr[0]->get_content())
-                                       .'\')';
-                               phpCAS::traceEnd(FALSE);
-                               return FALSE;
-                       } else {
-                               phpCAS::trace('neither <proxySuccess> nor <proxyFailure> found');
-                       }
-               }
-               
-               // at this step, we are sure that the response of the CAS server was ill-formed
-               $err_code = PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE;
-               $err_msg = 'Invalid response from the CAS server (response=`'.$cas_response.'\')';
-               
-               phpCAS::traceEnd(FALSE);
-               return FALSE;
-               }
-       
-       // ########################################################################
-       // ACCESS TO EXTERNAL SERVICES
-       // ########################################################################
-       
-       /**
-        * This method is used to acces a remote URL.
-        *
-        * @param $url the URL to access.
-        * @param $cookies an array containing cookies strings such as 'name=val'
-        * @param $headers an array containing the HTTP header lines of the response
-        * (an empty array on failure).
-        * @param $body the body of the response, as a string (empty on failure).
-        * @param $err_msg an error message, filled on failure.
-        *
-        * @return TRUE on success, FALSE otherwise (in this later case, $err_msg
-        * contains an error message).
-        *
-        * @private
-        */
-       function readURL($url,$cookies,&$headers,&$body,&$err_msg)
-               {
-               phpCAS::traceBegin();
-               $headers = '';
-               $body = '';
-               $err_msg = '';
-               
-               $res = TRUE;
-               
-               // initialize the CURL session
-               $ch = curl_init($url);
-               
-               if (version_compare(PHP_VERSION,'5.1.3','>=')) {
-                       //only avaible in php5
-                       curl_setopt_array($ch, $this->_curl_options);
-               } else {
-                       foreach ($this->_curl_options as $key => $value) {
-                               curl_setopt($ch, $key, $value);
-                       }
-               }
-               
-               if ($this->_cas_server_cert == '' && $this->_cas_server_ca_cert == '' && !$this->_no_cas_server_validation) {
-                       phpCAS::error('one of the methods phpCAS::setCasServerCert(), phpCAS::setCasServerCACert() or phpCAS::setNoCasServerValidation() must be called.');
-               }
-               if ($this->_cas_server_cert != '' && $this->_cas_server_ca_cert != '') {
-                       // This branch added by IDMS. Seems phpCAS implementor got a bit confused about the curl options CURLOPT_SSLCERT and CURLOPT_CAINFO
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
-                       curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
-                       curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
-                       curl_setopt($ch, CURLOPT_VERBOSE, '1');
-                       phpCAS::trace('CURL: Set all required opts for mutual authentication ------');
-               } else if ($this->_cas_server_cert != '' ) {
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
-                       curl_setopt($ch, CURLOPT_SSLCERT, $this->_cas_server_cert);
-               } else if ($this->_cas_server_ca_cert != '') {
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
-                       curl_setopt($ch, CURLOPT_CAINFO, $this->_cas_server_ca_cert);
-               } else {
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
-                       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
-               }
-               
-               // return the CURL output into a variable
-               curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
-               // get the HTTP header with a callback
-               $this->_curl_headers = array(); // empty the headers array
-               curl_setopt($ch, CURLOPT_HEADERFUNCTION, array($this, '_curl_read_headers'));
-               // add cookies headers
-               if ( is_array($cookies) ) {
-                       curl_setopt($ch,CURLOPT_COOKIE,implode(';',$cookies));
-               }
-               // add extra stuff if SAML
-               if ($this->hasSA()) {
-                       $more_headers = array ("soapaction: http://www.oasis-open.org/committees/security",
-                               "cache-control: no-cache",
-                               "pragma: no-cache",
-                               "accept: text/xml",
-                               "connection: keep-alive",
-                       "content-type: text/xml");
-                       
-                       curl_setopt($ch, CURLOPT_HTTPHEADER, $more_headers);
-                       curl_setopt($ch, CURLOPT_POST, 1);
-                       $data = $this->buildSAMLPayload();
-                       //phpCAS::trace('SAML Payload: '.print_r($data, TRUE));
-                       curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
-               }
-               // perform the query
-               $buf = curl_exec ($ch);
-               //phpCAS::trace('CURL: Call completed. Response body is: \''.$buf.'\'');
-               if ( $buf === FALSE ) {
-                       phpCAS::trace('curl_exec() failed');
-                       $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch);
-                       //phpCAS::trace('curl error: '.$err_msg);
-                       // close the CURL session
-                       curl_close ($ch);
-                       $res = FALSE;
-               } else {
-                       // close the CURL session
-                       curl_close ($ch);
-                       
-                       $headers = $this->_curl_headers;
-                       $body = $buf;
-               }
-               
-               phpCAS::traceEnd($res);
-               return $res;
-               }
-       
-       /**
-        * This method is used to build the SAML POST body sent to /samlValidate URL.
-        *
-        * @return the SOAP-encased SAMLP artifact (the ticket).
-        *
-        * @private
-        */
-       function buildSAMLPayload()
-               {
-               phpCAS::traceBegin();
-               
-               //get the ticket
-               $sa = $this->getSA();
-               //phpCAS::trace("SA: ".$sa);
-               
-               $body=SAML_SOAP_ENV.SAML_SOAP_BODY.SAMLP_REQUEST.SAML_ASSERTION_ARTIFACT.$sa.SAML_ASSERTION_ARTIFACT_CLOSE.SAMLP_REQUEST_CLOSE.SAML_SOAP_BODY_CLOSE.SAML_SOAP_ENV_CLOSE;
-               
-               phpCAS::traceEnd($body);
-               return ($body);
-               }
-       
-       /**
-        * This method is the callback used by readURL method to request HTTP headers.
-        */
-       var $_curl_headers = array();
-       function _curl_read_headers($ch, $header)
-               {
-               $this->_curl_headers[] = $header;
-               return strlen($header);
-               }
-       
-       /**
-        * This method is used to access an HTTP[S] service.
-        * 
-        * @param $url the service to access.
-        * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
-        * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
-        * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
-        * @param $output the output of the service (also used to give an error
-        * message on failure).
-        *
-        * @return TRUE on success, FALSE otherwise (in this later case, $err_code
-        * gives the reason why it failed and $output contains an error message).
-        *
-        * @public
-        */
-       function serviceWeb($url,&$err_code,&$output)
-               {
-               phpCAS::traceBegin();
-               // at first retrieve a PT
-               $pt = $this->retrievePT($url,$err_code,$output);
-               
-               $res = TRUE;
-               
-               // test if PT was retrieved correctly
-               if ( !$pt ) {
-                       // note: $err_code and $err_msg are filled by CASClient::retrievePT()
-                       phpCAS::trace('PT was not retrieved correctly');
-                       $res = FALSE;
-               } else {
-                       // add cookies if necessary
-                       $cookies = $this->getCookies($url);
-                       
-                       // build the URL including the PT
-                       if ( strstr($url,'?') === FALSE ) {
-                               $service_url = $url.'?ticket='.$pt;
-                       } else {
-                               $service_url = $url.'&ticket='.$pt;
-                       }
-                       
-                       phpCAS::trace('reading URL`'.$service_url.'\'');
-                       if ( !$this->readURL($service_url,$cookies,$headers,$output,$err_msg) ) {
-                               phpCAS::trace('could not read URL`'.$service_url.'\'');
-                               $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
-                               // give an error message
-                               $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
-                                       $service_url,
-                                       $err_msg);
-                               $res = FALSE;
-                       } else {
-                               // URL has been fetched, extract the cookies
-                               phpCAS::trace('URL`'.$service_url.'\' has been read, storing cookies:');
-                               $this->setCookies($headers,$url);
-                               // Check for a possible redirect (phpCAS authenticiation redirect after ticket removal)
-                               foreach($headers as $header){
-                                       if (preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches))
-                                       {
-                                               $redirect_url = trim(array_pop($matches));
-                                               phpCAS :: trace('Found redirect:'.$redirect_url);
-                                               $cookies = $this->getCookies($redirect_url);
-                                               phpCAS::trace('reading URL`'.$redirect_url.'\'');
-                                               if ( !$this->readURL($redirect_url,$cookies,$headers,$output,$err_msg) ) {
-                                                       phpCAS::trace('could not read URL`'.$redirect_url.'\'');
-                                                       $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
-                                                       // give an error message
-                                                       $output = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
-                                                               $service_url,
-                                                               $err_msg);
-                                                       $res = FALSE;
-                                               } else {
-                                                       // URL has been fetched, extract the cookies
-                                                       phpCAS::trace('URL`'.$redirect_url.'\' has been read, storing cookies:');
-                                                       $this->setCookies($headers,$redirect_url);
-                                               }
-                                               break;
-                                       }
-                               }
-                       }
-               }
-               
-               phpCAS::traceEnd($res);
-               return $res;
-               }
-       
-       /**
-        * This method stores cookies from a HTTP Header in the session
-        * @param $header HTTP Header
-        * @param $url the url the Header is from
-        */
-       
-       function setCookies($headers,$url){
-               phpCAS::traceBegin();
-               foreach ( $headers as $header ) {
-                       // test if the header is a cookie
-                       if ( preg_match('/^Set-Cookie:/',$header) ) {
-                               // the header is a cookie, remove the beginning
-                               $header_val = preg_replace('/^Set-Cookie: */','',$header);
-                               // extract interesting information
-                               $name_val = strtok($header_val,'; ');
-                               // extract the name and the value of the cookie
-                               $cookie_name = strtok($name_val,'=');
-                               $cookie_val = strtok('=');
-                               // store the cookie 
-                               $_SESSION['phpCAS']['services'][$url]['cookies'][$cookie_name] = $cookie_val;
-                               phpCAS::trace($cookie_name.' -> '.$cookie_val);
-                       }
-               }
-               phpCAS::traceEnd();
-       }
-       
-       /**
-        * This method get the cookies from the session
-        */
-        
-       function getCookies($url){
-               $cookies = array();
-               if ( isset($_SESSION['phpCAS']['services'][$url]['cookies']) && 
-                               is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) {
-                       foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { 
-                               $cookies[] = $name.'='.$val;
-                       }
-               }
-               return $cookies;
-       }
-       
-       /**
-        * This method is used to access an IMAP/POP3/NNTP service.
-        * 
-        * @param $url a string giving the URL of the service, including the mailing box
-        * for IMAP URLs, as accepted by imap_open().
-        * @param $service a string giving for CAS retrieve Proxy ticket
-        * @param $flags options given to imap_open().
-        * @param $err_code an error code Possible values are PHPCAS_SERVICE_OK (on
-        * success), PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
-        * PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_NOT AVAILABLE.
-        * @param $err_msg an error message on failure
-        * @param $pt the Proxy Ticket (PT) retrieved from the CAS server to access the URL
-        * on success, FALSE on error).
-        *
-        * @return an IMAP stream on success, FALSE otherwise (in this later case, $err_code
-        * gives the reason why it failed and $err_msg contains an error message).
-        *
-        * @public
-        */
-       function serviceMail($url,$service,$flags,&$err_code,&$err_msg,&$pt)
-               {
-               phpCAS::traceBegin();
-               // at first retrieve a PT
-               $pt = $this->retrievePT($service,$err_code,$output);
-               
-               $stream = FALSE;
-               
-               // test if PT was retrieved correctly
-               if ( !$pt ) {
-                       // note: $err_code and $err_msg are filled by CASClient::retrievePT()
-                       phpCAS::trace('PT was not retrieved correctly');
-               } else {
-                       phpCAS::trace('opening IMAP URL `'.$url.'\'...');
-                       $stream = @imap_open($url,$this->getUser(),$pt,$flags);
-                       if ( !$stream ) {
-                               phpCAS::trace('could not open URL');
-                               $err_code = PHPCAS_SERVICE_NOT_AVAILABLE;
-                               // give an error message
-                               $err_msg = sprintf($this->getString(CAS_STR_SERVICE_UNAVAILABLE),
-                                       $service_url,
-                                       var_export(imap_errors(),TRUE));
-                               $pt = FALSE;
-                               $stream = FALSE;
-                       } else {
-                               phpCAS::trace('ok');
-                       }
-               }
-               
-               phpCAS::traceEnd($stream);
-               return $stream;
-               }
-       
-       /** @} */
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                  PROXIED CLIENT FEATURES (CAS 2.0)                 XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       // ########################################################################
-       //  PT
-       // ########################################################################
-       /**
-        * @addtogroup internalProxied
-        * @{
-        */  
-       
-       /**
-        * the Proxy Ticket provided in the URL of the request if present
-        * (empty otherwise). Written by CASClient::CASClient(), read by 
-        * CASClient::getPT() and CASClient::hasPGT().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_pt = '';
-       
-       /**
-        * This method returns the Proxy Ticket provided in the URL of the request.
-        * @return The proxy ticket.
-        * @private
-        */
-       function getPT()
-               {
-               //      return 'ST'.substr($this->_pt, 2);
-               return $this->_pt;
-               }
-       
-       /**
-        * This method stores the Proxy Ticket.
-        * @param $pt The Proxy Ticket.
-        * @private
-        */
-       function setPT($pt)
-               { $this->_pt = $pt; }
-       
-       /**
-        * This method tells if a Proxy Ticket was stored.
-        * @return TRUE if a Proxy Ticket has been stored.
-        * @private
-        */
-       function hasPT()
-               { return !empty($this->_pt); }
-       /**
-        * This method returns the SAML Ticket provided in the URL of the request.
-        * @return The SAML ticket.
-        * @private
-        */
-       function getSA()
-               { return 'ST'.substr($this->_sa, 2); }
-       
-       /**
-        * This method stores the SAML Ticket.
-        * @param $sa The SAML Ticket.
-        * @private
-        */
-       function setSA($sa)
-               { $this->_sa = $sa; }
-       
-       /**
-        * This method tells if a SAML Ticket was stored.
-        * @return TRUE if a SAML Ticket has been stored.
-        * @private
-        */
-       function hasSA()
-               { return !empty($this->_sa); }
-       
-       /** @} */
-       // ########################################################################
-       //  PT VALIDATION
-       // ########################################################################
-       /**
-        * @addtogroup internalProxied
-        * @{
-        */  
-       
-       /**
-        * This method is used to validate a ST or PT; halt on failure
-        * Used for all CAS 2.0 validations
-        * @return bool TRUE when successfull, halt otherwise by calling CASClient::authError().
-        *
-        * @private
-        */
-       function validatePT(&$validate_url,&$text_response,&$tree_response)
-               {
-               phpCAS::traceBegin();
-               // build the URL to validate the ticket
-               $validate_url = $this->getServerProxyValidateURL().'&ticket='.$this->getPT();
-               
-               if ( $this->isProxy() ) {
-                       // pass the callback url for CAS proxies
-                       $validate_url .= '&pgtUrl='.urlencode($this->getCallbackURL());
-               }
-               
-               // open and read the URL
-               if ( !$this->readURL($validate_url,''/*cookies*/,$headers,$text_response,$err_msg) ) {
-                       phpCAS::trace('could not open URL \''.$validate_url.'\' to validate ('.$err_msg.')');
-                       $this->authError('PT not validated',
-                               $validate_url,
-                               TRUE/*$no_response*/);
-               }
-               
-               // read the response of the CAS server into a DOM object
-               if ( !($dom = domxml_open_mem($text_response))) {
-                       // read failed
-                       $this->authError('PT not validated',
-                               $validate_url,
-                               FALSE/*$no_response*/,
-                               TRUE/*$bad_response*/,
-                               $text_response);
-               }
-               // read the root node of the XML tree
-               if ( !($tree_response = $dom->document_element()) ) {
-                       // read failed
-                       $this->authError('PT not validated',
-                               $validate_url,
-                               FALSE/*$no_response*/,
-                               TRUE/*$bad_response*/,
-                               $text_response);
-               }
-               // insure that tag name is 'serviceResponse'
-               if ( $tree_response->node_name() != 'serviceResponse' ) {
-                       // bad root node
-                       $this->authError('PT not validated',
-                               $validate_url,
-                               FALSE/*$no_response*/,
-                               TRUE/*$bad_response*/,
-                               $text_response);
-               }
-               if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationSuccess")) != 0) {
-                       // authentication succeded, extract the user name
-                       if ( sizeof($arr = $tree_response->get_elements_by_tagname("user")) == 0) {
-                               // no user specified => error
-                               $this->authError('PT not validated',
-                                       $validate_url,
-                                       FALSE/*$no_response*/,
-                                       TRUE/*$bad_response*/,
-                                       $text_response);
-                       }
-                       $this->setUser(trim($arr[0]->get_content()));
-                       
-               } else if ( sizeof($arr = $tree_response->get_elements_by_tagname("authenticationFailure")) != 0) {
-                       // authentication succeded, extract the error code and message
-                       $this->authError('PT not validated',
-                               $validate_url,
-                               FALSE/*$no_response*/,
-                               FALSE/*$bad_response*/,
-                               $text_response,
-                               $arr[0]->get_attribute('code')/*$err_code*/,
-                               trim($arr[0]->get_content())/*$err_msg*/);
-               } else {
-                       $this->authError('PT not validated',
-                               $validate_url,  
-                               FALSE/*$no_response*/,
-                               TRUE/*$bad_response*/,
-                               $text_response);
-               }
-               
-               $this->renameSession($this->getPT());
-               // at this step, PT has been validated and $this->_user has been set,
-               
-               phpCAS::traceEnd(TRUE);
-               return TRUE;
-               }
-       
-       /** @} */
-       
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       // XX                                                                    XX
-       // XX                               MISC                                 XX
-       // XX                                                                    XX
-       // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-       
-       /**
-        * @addtogroup internalMisc
-        * @{
-        */  
-       
-       // ########################################################################
-       //  URL
-       // ########################################################################
-       /**
-        * the URL of the current request (without any ticket CGI parameter). Written 
-        * and read by CASClient::getURL().
-        *
-        * @hideinitializer
-        * @private
-        */
-       var $_url = '';
-       
-       /**
-        * This method returns the URL of the current request (without any ticket
-        * CGI parameter).
-        *
-        * @return The URL
-        *
-        * @private
-        */
-       function getURL()
-               {
-               phpCAS::traceBegin();
-               // the URL is built when needed only
-               if ( empty($this->_url) ) {
-                       $final_uri = '';
-                       // remove the ticket if present in the URL
-                       $final_uri = ($this->isHttps()) ? 'https' : 'http';
-                       $final_uri .= '://';
-                       /* replaced by Julien Marchal - v0.4.6
-                        * $this->_url .= $_SERVER['SERVER_NAME'];
-                        */
-                       if(empty($_SERVER['HTTP_X_FORWARDED_SERVER'])){
-                               /* replaced by teedog - v0.4.12
-                                * $this->_url .= $_SERVER['SERVER_NAME'];
-                                */
-                               if (empty($_SERVER['SERVER_NAME'])) {
-                                       $server_name = $_SERVER['HTTP_HOST'];
-                               } else {
-                                       $server_name = $_SERVER['SERVER_NAME'];
-                               }
-                       } else {
-                               $server_name = $_SERVER['HTTP_X_FORWARDED_SERVER'];
-                       }
-                       $final_uri .= $server_name;
-                       if (!strpos($server_name, ':')) {
-                               if ( ($this->isHttps() && $_SERVER['SERVER_PORT']!=443)
-                                               || (!$this->isHttps() && $_SERVER['SERVER_PORT']!=80) ) {
-                                       $final_uri .= ':';
-                                       $final_uri .= $_SERVER['SERVER_PORT'];
-                               }
-                       }
-                       
-                       $request_uri    = explode('?', $_SERVER['REQUEST_URI'], 2);
-                       $final_uri              .= $request_uri[0];
-                       
-                       if (isset($request_uri[1]) && $request_uri[1])
-                       {
-                               $query_string   = $this->removeParameterFromQueryString('ticket', $request_uri[1]);
-                               
-                               // If the query string still has anything left, append it to the final URI
-                               if ($query_string !== '')
-                                       $final_uri      .= "?$query_string";
-                               
-                       }
-                       
-                       phpCAS::trace("Final URI: $final_uri");
-                       $this->setURL($final_uri);
-               }
-               phpCAS::traceEnd($this->_url);
-               return $this->_url;
-       }
-       
-
-               
-       /**
-        * Removes a parameter from a query string
-        * 
-        * @param string $parameterName 
-        * @param string $queryString
-        * @return string
-        *
-        * @link http://stackoverflow.com/questions/1842681/regular-expression-to-remove-one-parameter-from-query-string
-        */
-       function removeParameterFromQueryString($parameterName, $queryString)
-       {
-               $parameterName  = preg_quote($parameterName);
-               return preg_replace("/&$parameterName(=[^&]*)?|^$parameterName(=[^&]*)?&?/", '', $queryString);
-       }
-
-       
-       /**
-        * This method sets the URL of the current request 
-        *
-        * @param $url url to set for service
-        *
-        * @private
-        */
-       function setURL($url)
-               {
-               $this->_url = $url;
-               }
-       
-       // ########################################################################
-       //  AUTHENTICATION ERROR HANDLING
-       // ########################################################################
-       /**
-        * This method is used to print the HTML output when the user was not authenticated.
-        *
-        * @param $failure the failure that occured
-        * @param $cas_url the URL the CAS server was asked for
-        * @param $no_response the response from the CAS server (other 
-        * parameters are ignored if TRUE)
-        * @param $bad_response bad response from the CAS server ($err_code
-        * and $err_msg ignored if TRUE)
-        * @param $cas_response the response of the CAS server
-        * @param $err_code the error code given by the CAS server
-        * @param $err_msg the error message given by the CAS server
-        *
-        * @private
-        */
-       function authError($failure,$cas_url,$no_response,$bad_response='',$cas_response='',$err_code='',$err_msg='')
-               {
-               phpCAS::traceBegin();
-               
-               $this->printHTMLHeader($this->getString(CAS_STR_AUTHENTICATION_FAILED));
-               printf($this->getString(CAS_STR_YOU_WERE_NOT_AUTHENTICATED),htmlentities($this->getURL()),$_SERVER['SERVER_ADMIN']);
-               phpCAS::trace('CAS URL: '.$cas_url);
-               phpCAS::trace('Authentication failure: '.$failure);
-               if ( $no_response ) {
-                       phpCAS::trace('Reason: no response from the CAS server');
-               } else {
-                       if ( $bad_response ) {
-                               phpCAS::trace('Reason: bad response from the CAS server');
-                       } else {
-                               switch ($this->getServerVersion()) {
-                                       case CAS_VERSION_1_0:
-                                               phpCAS::trace('Reason: CAS error');
-                                               break;
-                                       case CAS_VERSION_2_0:
-                                               if ( empty($err_code) )
-                                                       phpCAS::trace('Reason: no CAS error');
-                                               else
-                                                       phpCAS::trace('Reason: ['.$err_code.'] CAS error: '.$err_msg);
-                                               break;
-                               }
-                       }
-                       phpCAS::trace('CAS response: '.$cas_response);
-               }
-               $this->printHTMLFooter();
-               phpCAS::traceExit();
-               exit();
-               }
-       
-       /** @} */
-}
-
-?>
diff --git a/CAS/CAS/domxml-php4-to-php5.php b/CAS/CAS/domxml-php4-to-php5.php
deleted file mode 100644 (file)
index 966836d..0000000
+++ /dev/null
@@ -1,499 +0,0 @@
-<?php
-/*
-       Requires PHP5, uses built-in DOM extension.
-       To be used in PHP4 scripts using DOMXML extension: allows PHP4/DOMXML scripts to run on PHP5/DOM.
-       (Optional: requires PHP5/XSL extension for domxml_xslt functions, PHP>=5.1 for XPath evaluation functions, and PHP>=5.1/libxml for DOMXML error reports)
-
-       Typical use:
-       {
-               if (PHP_VERSION>='5')
-                       require_once('domxml-php4-to-php5.php');
-       }
-
-       Version 1.21.1a, 2009-03-13, http://alexandre.alapetite.fr/doc-alex/domxml-php4-php5/
-
-       ------------------------------------------------------------------
-       Written by Alexandre Alapetite, http://alexandre.alapetite.fr/cv/
-
-       Copyright 2004-2009, GNU Lesser General Public License,
-       http://www.gnu.org/licenses/lgpl.html
-
-       This program is free software: you can redistribute it and/or modify
-       it under the terms of the GNU Lesser General Public License as published by
-       the Free Software Foundation, either version 3 of the License, or
-       (at your option) any later version.
-       This program is distributed in the hope that it will be useful,
-       but WITHOUT ANY WARRANTY; without even the implied warranty of
-       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-       GNU Lesser General Public License for more details.
-       You should have received a copy of the GNU Lesser General Public License
-       along with this program. If not, see <http://www.gnu.org/licenses/lgpl.html>
-
-       == Rights and obligations ==
-       - Attribution: You must give the original author credit.
-       - Share Alike: If you alter or transform this library,
-          you may distribute the resulting library only under the same license GNU/LGPL.
-       - In case of jurisdiction dispute, the French law is authoritative.
-       - Any of these conditions can be waived if you get permission from Alexandre Alapetite.
-       - Not required, but please send to Alexandre Alapetite the modifications you make,
-          in order to improve this file for the benefit of everybody.
-
-       If you want to distribute this code, please do it as a link to:
-       http://alexandre.alapetite.fr/doc-alex/domxml-php4-php5/
-*/
-
-define('DOMXML_LOAD_PARSING',0);
-define('DOMXML_LOAD_VALIDATING',1);
-define('DOMXML_LOAD_RECOVERING',2);
-define('DOMXML_LOAD_SUBSTITUTE_ENTITIES',4);
-//define('DOMXML_LOAD_COMPLETE_ATTRS',8);
-define('DOMXML_LOAD_DONT_KEEP_BLANKS',16);
-
-function domxml_new_doc($version) {return new php4DOMDocument();}
-function domxml_new_xmldoc($version) {return new php4DOMDocument();}
-function domxml_open_file($filename,$mode=DOMXML_LOAD_PARSING,&$error=null)
-{
-       $dom=new php4DOMDocument($mode);
-       $errorMode=(func_num_args()>2)&&defined('LIBXML_VERSION');
-       if ($errorMode) libxml_use_internal_errors(true);
-       if (!$dom->myDOMNode->load($filename)) $dom=null;
-       if ($errorMode)
-       {
-               $error=array_map('_error_report',libxml_get_errors());
-               libxml_clear_errors();
-       }
-       return $dom;
-}
-function domxml_open_mem($str,$mode=DOMXML_LOAD_PARSING,&$error=null)
-{
-       $dom=new php4DOMDocument($mode);
-       $errorMode=(func_num_args()>2)&&defined('LIBXML_VERSION');
-       if ($errorMode) libxml_use_internal_errors(true);
-       if (!$dom->myDOMNode->loadXML($str)) $dom=null;
-       if ($errorMode)
-       {
-               $error=array_map('_error_report',libxml_get_errors());
-               libxml_clear_errors();
-       }
-       return $dom;
-}
-function html_doc($html_doc,$from_file=false)
-{
-       $dom=new php4DOMDocument();
-       if ($from_file) $result=$dom->myDOMNode->loadHTMLFile($html_doc);
-       else $result=$dom->myDOMNode->loadHTML($html_doc);
-       return $result ? $dom : null;
-}
-function html_doc_file($filename) {return html_doc($filename,true);}
-function xmldoc($str) {return domxml_open_mem($str);}
-function xmldocfile($filename) {return domxml_open_file($filename);}
-function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->xpath_eval($eval_str,$contextnode);}
-function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);}
-function xpath_register_ns($xpath_context,$prefix,$namespaceURI) {return $xpath_context->myDOMXPath->registerNamespace($prefix,$namespaceURI);}
-function _entityDecode($text) {return html_entity_decode(strtr($text,array('&apos;'=>'\'')),ENT_QUOTES,'UTF-8');}
-function _error_report($error) {return array('errormessage'=>$error->message,'nodename'=>'','line'=>$error->line,'col'=>$error->column)+($error->file==''?array():array('directory'=>dirname($error->file),'file'=>basename($error->file)));}
-
-class php4DOMAttr extends php4DOMNode
-{
-       function __get($name)
-       {
-               if ($name==='name') return $this->myDOMNode->name;
-               else return parent::__get($name);
-       }
-       function name() {return $this->myDOMNode->name;}
-       function set_content($text) {}
-       //function set_value($content) {return $this->myDOMNode->value=htmlspecialchars($content,ENT_QUOTES);}
-       function specified() {return $this->myDOMNode->specified;}
-       function value() {return $this->myDOMNode->value;}
-}
-
-class php4DOMDocument extends php4DOMNode
-{
-       function php4DOMDocument($mode=DOMXML_LOAD_PARSING)
-       {
-               $this->myDOMNode=new DOMDocument();
-               $this->myOwnerDocument=$this;
-               if ($mode & DOMXML_LOAD_VALIDATING) $this->myDOMNode->validateOnParse=true;
-               if ($mode & DOMXML_LOAD_RECOVERING) $this->myDOMNode->recover=true;
-               if ($mode & DOMXML_LOAD_SUBSTITUTE_ENTITIES) $this->myDOMNode->substituteEntities=true;
-               if ($mode & DOMXML_LOAD_DONT_KEEP_BLANKS) $this->myDOMNode->preserveWhiteSpace=false;
-       }
-       function add_root($name)
-       {
-               if ($this->myDOMNode->hasChildNodes()) $this->myDOMNode->removeChild($this->myDOMNode->firstChild);
-               return new php4DOMElement($this->myDOMNode->appendChild($this->myDOMNode->createElement($name)),$this->myOwnerDocument);
-       }
-       function create_attribute($name,$value)
-       {
-               $myAttr=$this->myDOMNode->createAttribute($name);
-               $myAttr->value=htmlspecialchars($value,ENT_QUOTES);
-               return new php4DOMAttr($myAttr,$this);
-       }
-       function create_cdata_section($content) {return new php4DOMNode($this->myDOMNode->createCDATASection($content),$this);}
-       function create_comment($data) {return new php4DOMNode($this->myDOMNode->createComment($data),$this);}
-       function create_element($name) {return new php4DOMElement($this->myDOMNode->createElement($name),$this);}
-       function create_element_ns($uri,$name,$prefix=null)
-       {
-               if ($prefix==null) $prefix=$this->myDOMNode->lookupPrefix($uri);
-               if (($prefix==null)&&(($this->myDOMNode->documentElement==null)||(!$this->myDOMNode->documentElement->isDefaultNamespace($uri)))) $prefix='a'.sprintf('%u',crc32($uri));
-               return new php4DOMElement($this->myDOMNode->createElementNS($uri,$prefix==null ? $name : $prefix.':'.$name),$this);
-       }
-       function create_entity_reference($content) {return new php4DOMNode($this->myDOMNode->createEntityReference($content),$this);} //By Walter Ebert 2007-01-22
-       function create_processing_instruction($target,$data=''){return new php4DomProcessingInstruction($this->myDOMNode->createProcessingInstruction($target,$data),$this);}
-       function create_text_node($content) {return new php4DOMText($this->myDOMNode->createTextNode($content),$this);}
-       function document_element() {return parent::_newDOMElement($this->myDOMNode->documentElement,$this);}
-       function dump_file($filename,$compressionmode=false,$format=false)
-       {
-               $format0=$this->myDOMNode->formatOutput;
-               $this->myDOMNode->formatOutput=$format;
-               $res=$this->myDOMNode->save($filename);
-               $this->myDOMNode->formatOutput=$format0;
-               return $res;
-       }
-       function dump_mem($format=false,$encoding=false)
-       {
-               $format0=$this->myDOMNode->formatOutput;
-               $this->myDOMNode->formatOutput=$format;
-               $encoding0=$this->myDOMNode->encoding;
-               if ($encoding) $this->myDOMNode->encoding=$encoding;
-               $dump=$this->myDOMNode->saveXML();
-               $this->myDOMNode->formatOutput=$format0;
-               if ($encoding) $this->myDOMNode->encoding= $encoding0=='' ? 'UTF-8' : $encoding0; //UTF-8 is XML default encoding
-               return $dump;
-       }
-       function free()
-       {
-               if ($this->myDOMNode->hasChildNodes()) $this->myDOMNode->removeChild($this->myDOMNode->firstChild);
-               $this->myDOMNode=null;
-               $this->myOwnerDocument=null;
-       }
-       function get_element_by_id($id) {return parent::_newDOMElement($this->myDOMNode->getElementById($id),$this);}
-       function get_elements_by_tagname($name)
-       {
-               $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
-               $nodeSet=array();
-               $i=0;
-               if (isset($myDOMNodeList))
-                       while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMElement($node,$this);
-               return $nodeSet;
-       }
-       function html_dump_mem() {return $this->myDOMNode->saveHTML();}
-       function root() {return parent::_newDOMElement($this->myDOMNode->documentElement,$this);}
-       function xinclude() {return $this->myDOMNode->xinclude();}
-       function xpath_new_context() {return new php4DOMXPath($this);}
-}
-
-class php4DOMElement extends php4DOMNode
-{
-       function add_namespace($uri,$prefix)
-       {
-               if ($this->myDOMNode->hasAttributeNS('http://www.w3.org/2000/xmlns/',$prefix)) return false;
-               else
-               {
-                       $this->myDOMNode->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:'.$prefix,$uri); //By Daniel Walker 2006-09-08
-                       return true;
-               }
-       }
-       function get_attribute($name) {return $this->myDOMNode->getAttribute($name);}
-       function get_attribute_node($name) {return parent::_newDOMElement($this->myDOMNode->getAttributeNode($name),$this->myOwnerDocument);}
-       function get_elements_by_tagname($name)
-       {
-               $myDOMNodeList=$this->myDOMNode->getElementsByTagName($name);
-               $nodeSet=array();
-               $i=0;
-               if (isset($myDOMNodeList))
-                       while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument);
-               return $nodeSet;
-       }
-       function has_attribute($name) {return $this->myDOMNode->hasAttribute($name);}
-       function remove_attribute($name) {return $this->myDOMNode->removeAttribute($name);}
-       function set_attribute($name,$value)
-       {
-               //return $this->myDOMNode->setAttribute($name,$value); //Does not return a DomAttr
-               $myAttr=$this->myDOMNode->ownerDocument->createAttribute($name);
-               $myAttr->value=htmlspecialchars($value,ENT_QUOTES); //Entity problem reported by AL-DesignWorks 2007-09-07
-               $this->myDOMNode->setAttributeNode($myAttr);
-               return new php4DOMAttr($myAttr,$this->myOwnerDocument);
-       }
-       /*function set_attribute_node($attr)
-       {
-               $this->myDOMNode->setAttributeNode($this->_importNode($attr));
-               return $attr;
-       }*/
-       function set_name($name)
-       {
-               if ($this->myDOMNode->prefix=='') $newNode=$this->myDOMNode->ownerDocument->createElement($name);
-               else $newNode=$this->myDOMNode->ownerDocument->createElementNS($this->myDOMNode->namespaceURI,$this->myDOMNode->prefix.':'.$name);
-               $myDOMNodeList=$this->myDOMNode->attributes;
-               $i=0;
-               if (isset($myDOMNodeList))
-                       while ($node=$myDOMNodeList->item($i++))
-                               if ($node->namespaceURI=='') $newNode->setAttribute($node->name,$node->value);
-                               else $newNode->setAttributeNS($node->namespaceURI,$node->nodeName,$node->value);
-               $myDOMNodeList=$this->myDOMNode->childNodes;
-               if (isset($myDOMNodeList))
-                       while ($node=$myDOMNodeList->item(0)) $newNode->appendChild($node);
-               $this->myDOMNode->parentNode->replaceChild($newNode,$this->myDOMNode);
-               $this->myDOMNode=$newNode;
-               return true;
-       }
-       function tagname() {return $this->tagname;}
-}
-
-class php4DOMNode
-{
-       public $myDOMNode;
-       public $myOwnerDocument;
-       function php4DOMNode($aDomNode,$aOwnerDocument)
-       {
-               $this->myDOMNode=$aDomNode;
-               $this->myOwnerDocument=$aOwnerDocument;
-       }
-       function __get($name)
-       {
-               switch ($name)
-               {
-                       case 'type': return $this->myDOMNode->nodeType;
-                       case 'tagname': return ($this->myDOMNode->nodeType===XML_ELEMENT_NODE) ? $this->myDOMNode->localName : $this->myDOMNode->tagName; //Avoid namespace prefix for DOMElement
-                       case 'content': return $this->myDOMNode->textContent;
-                       case 'value': return $this->myDOMNode->value;
-                       default:
-                               $myErrors=debug_backtrace();
-                               trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE);
-                               return false;
-               }
-       }
-       function add_child($newnode) {return $this->append_child($newnode);}
-       function add_namespace($uri,$prefix) {return false;}
-       function append_child($newnode) {return self::_newDOMElement($this->myDOMNode->appendChild($this->_importNode($newnode)),$this->myOwnerDocument);}
-       function append_sibling($newnode) {return self::_newDOMElement($this->myDOMNode->parentNode->appendChild($this->_importNode($newnode)),$this->myOwnerDocument);}
-       function attributes()
-       {
-               $myDOMNodeList=$this->myDOMNode->attributes;
-               if (!(isset($myDOMNodeList)&&$this->myDOMNode->hasAttributes())) return null;
-               $nodeSet=array();
-               $i=0;
-               while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument);
-               return $nodeSet;
-       }
-       function child_nodes()
-       {
-               $myDOMNodeList=$this->myDOMNode->childNodes;
-               $nodeSet=array();
-               $i=0;
-               if (isset($myDOMNodeList))
-                       while ($node=$myDOMNodeList->item($i++)) $nodeSet[]=self::_newDOMElement($node,$this->myOwnerDocument);
-               return $nodeSet;
-       }
-       function children() {return $this->child_nodes();}
-       function clone_node($deep=false) {return self::_newDOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);}
-       //dump_node($node) should only be called on php4DOMDocument
-       function dump_node($node=null) {return $node==null ? $this->myOwnerDocument->myDOMNode->saveXML($this->myDOMNode) : $this->myOwnerDocument->myDOMNode->saveXML($node->myDOMNode);}
-       function first_child() {return self::_newDOMElement($this->myDOMNode->firstChild,$this->myOwnerDocument);}
-       function get_content() {return $this->myDOMNode->textContent;}
-       function has_attributes() {return $this->myDOMNode->hasAttributes();}
-       function has_child_nodes() {return $this->myDOMNode->hasChildNodes();}
-       function insert_before($newnode,$refnode) {return self::_newDOMElement($this->myDOMNode->insertBefore($this->_importNode($newnode),$refnode==null?null:$refnode->myDOMNode),$this->myOwnerDocument);}
-       function is_blank_node() {return ($this->myDOMNode->nodeType===XML_TEXT_NODE)&&preg_match('%^\s*$%',$this->myDOMNode->nodeValue);}
-       function last_child() {return self::_newDOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);}
-       function new_child($name,$content)
-       {
-               $mySubNode=$this->myDOMNode->ownerDocument->createElement($name);
-               $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode(_entityDecode($content)));
-               $this->myDOMNode->appendChild($mySubNode);
-               return new php4DOMElement($mySubNode,$this->myOwnerDocument);
-       }
-       function next_sibling() {return self::_newDOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);}
-       function node_name() {return ($this->myDOMNode->nodeType===XML_ELEMENT_NODE) ? $this->myDOMNode->localName : $this->myDOMNode->nodeName;} //Avoid namespace prefix for DOMElement
-       function node_type() {return $this->myDOMNode->nodeType;}
-       function node_value() {return $this->myDOMNode->nodeValue;}
-       function owner_document() {return $this->myOwnerDocument;}
-       function parent_node() {return self::_newDOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);}
-       function prefix() {return $this->myDOMNode->prefix;}
-       function previous_sibling() {return self::_newDOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);}
-       function remove_child($oldchild) {return self::_newDOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);}
-       function replace_child($newnode,$oldnode) {return self::_newDOMElement($this->myDOMNode->replaceChild($this->_importNode($newnode),$oldnode->myDOMNode),$this->myOwnerDocument);}
-       function replace_node($newnode) {return self::_newDOMElement($this->myDOMNode->parentNode->replaceChild($this->_importNode($newnode),$this->myDOMNode),$this->myOwnerDocument);}
-       function set_content($text) {return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode(_entityDecode($text)));} //Entity problem reported by AL-DesignWorks 2007-09-07
-       //function set_name($name) {return $this->myOwnerDocument->renameNode($this->myDOMNode,$this->myDOMNode->namespaceURI,$name);}
-       function set_namespace($uri,$prefix=null)
-       {//Contributions by Daniel Walker 2006-09-08
-               $nsprefix=$this->myDOMNode->lookupPrefix($uri);
-               if ($nsprefix==null)
-               {
-                       $nsprefix= $prefix==null ? $nsprefix='a'.sprintf('%u',crc32($uri)) : $prefix;
-                       if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE)
-                       {
-                               if (($prefix!=null)&&$this->myDOMNode->ownerElement->hasAttributeNS('http://www.w3.org/2000/xmlns/',$nsprefix)&&
-                                       ($this->myDOMNode->ownerElement->getAttributeNS('http://www.w3.org/2000/xmlns/',$nsprefix)!=$uri))
-                               {//Remove namespace
-                                       $parent=$this->myDOMNode->ownerElement;
-                                       $parent->removeAttributeNode($this->myDOMNode);
-                                       $parent->setAttribute($this->myDOMNode->localName,$this->myDOMNode->nodeValue);
-                                       $this->myDOMNode=$parent->getAttributeNode($this->myDOMNode->localName);
-                                       return;
-                               }
-                               $this->myDOMNode->ownerElement->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:'.$nsprefix,$uri);
-                       }
-               }
-               if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE)
-               {
-                       $parent=$this->myDOMNode->ownerElement;
-                       $parent->removeAttributeNode($this->myDOMNode);
-                       $parent->setAttributeNS($uri,$nsprefix.':'.$this->myDOMNode->localName,$this->myDOMNode->nodeValue);
-                       $this->myDOMNode=$parent->getAttributeNodeNS($uri,$this->myDOMNode->localName);
-               }
-               elseif ($this->myDOMNode->nodeType===XML_ELEMENT_NODE)
-               {
-                       $NewNode=$this->myDOMNode->ownerDocument->createElementNS($uri,$nsprefix.':'.$this->myDOMNode->localName);
-                       foreach ($this->myDOMNode->attributes as $n) $NewNode->appendChild($n->cloneNode(true));
-                       foreach ($this->myDOMNode->childNodes as $n) $NewNode->appendChild($n->cloneNode(true));
-                       $xpath=new DOMXPath($this->myDOMNode->ownerDocument);
-                       $myDOMNodeList=$xpath->query('namespace::*[name()!="xml"]',$this->myDOMNode); //Add old namespaces
-                       foreach ($myDOMNodeList as $n) $NewNode->setAttributeNS('http://www.w3.org/2000/xmlns/',$n->nodeName,$n->nodeValue); 
-                       $this->myDOMNode->parentNode->replaceChild($NewNode,$this->myDOMNode);
-                       $this->myDOMNode=$NewNode;
-               }
-       }
-       function unlink_node()
-       {
-               if ($this->myDOMNode->parentNode!=null)
-               {
-                       if ($this->myDOMNode->nodeType===XML_ATTRIBUTE_NODE) $this->myDOMNode->parentNode->removeAttributeNode($this->myDOMNode);
-                       else $this->myDOMNode->parentNode->removeChild($this->myDOMNode);
-               }
-       }
-       protected function _importNode($newnode) {return $this->myOwnerDocument===$newnode->myOwnerDocument ? $newnode->myDOMNode : $this->myOwnerDocument->myDOMNode->importNode($newnode->myDOMNode,true);} //To import DOMNode from another DOMDocument
-       static function _newDOMElement($aDOMNode,$aOwnerDocument)
-       {//Check the PHP5 DOMNode before creating a new associated PHP4 DOMNode wrapper
-               if ($aDOMNode==null) return null;
-               switch ($aDOMNode->nodeType)
-               {
-                       case XML_ELEMENT_NODE: return new php4DOMElement($aDOMNode,$aOwnerDocument);
-                       case XML_TEXT_NODE: return new php4DOMText($aDOMNode,$aOwnerDocument);
-                       case XML_ATTRIBUTE_NODE: return new php4DOMAttr($aDOMNode,$aOwnerDocument);
-                       case XML_PI_NODE: return new php4DomProcessingInstruction($aDOMNode,$aOwnerDocument);
-                       default: return new php4DOMNode($aDOMNode,$aOwnerDocument);
-               }
-       }
-}
-
-class php4DomProcessingInstruction extends php4DOMNode
-{
-       function data() {return $this->myDOMNode->data;}
-       function target() {return $this->myDOMNode->target;}
-}
-
-class php4DOMText extends php4DOMNode
-{
-       function __get($name)
-       {
-               if ($name==='tagname') return '#text';
-               else return parent::__get($name);
-       }
-       function tagname() {return '#text';}
-       function set_content($text) {$this->myDOMNode->nodeValue=$text; return true;}
-}
-
-if (!defined('XPATH_NODESET'))
-{
-       define('XPATH_UNDEFINED',0);
-       define('XPATH_NODESET',1);
-       define('XPATH_BOOLEAN',2);
-       define('XPATH_NUMBER',3);
-       define('XPATH_STRING',4);
-       /*define('XPATH_POINT',5);
-       define('XPATH_RANGE',6);
-       define('XPATH_LOCATIONSET',7);
-       define('XPATH_USERS',8);
-       define('XPATH_XSLT_TREE',9);*/
-}
-
-class php4DOMNodelist
-{
-       private $myDOMNodelist;
-       public $nodeset;
-       public $type=XPATH_UNDEFINED;
-       public $value;
-       function php4DOMNodelist($aDOMNodelist,$aOwnerDocument)
-       {
-               if (!isset($aDOMNodelist)) return; 
-               elseif (is_object($aDOMNodelist)||is_array($aDOMNodelist))
-               {
-                       if ($aDOMNodelist->length>0)
-                       {
-                               $this->myDOMNodelist=$aDOMNodelist;
-                               $this->nodeset=array();
-                               $this->type=XPATH_NODESET;
-                               $i=0;
-                               while ($node=$this->myDOMNodelist->item($i++)) $this->nodeset[]=php4DOMNode::_newDOMElement($node,$aOwnerDocument);
-                       }
-               }
-               elseif (is_int($aDOMNodelist)||is_float($aDOMNodelist))
-               {
-                       $this->type=XPATH_NUMBER;
-                       $this->value=$aDOMNodelist;
-               }
-               elseif (is_bool($aDOMNodelist))
-               {
-                       $this->type=XPATH_BOOLEAN;
-                       $this->value=$aDOMNodelist;
-               }
-               elseif (is_string($aDOMNodelist))
-               {
-                       $this->type=XPATH_STRING;
-                       $this->value=$aDOMNodelist;
-               }
-       }
-}
-
-class php4DOMXPath
-{
-       public $myDOMXPath;
-       private $myOwnerDocument;
-       function php4DOMXPath($dom_document)
-       {
-               //TODO: If $dom_document is a DomElement, make that default $contextnode and modify XPath. Ex: '/test'
-               $this->myOwnerDocument=$dom_document->myOwnerDocument;
-               $this->myDOMXPath=new DOMXPath($this->myOwnerDocument->myDOMNode);
-       }
-       function xpath_eval($eval_str,$contextnode=null)
-       {
-               if (method_exists($this->myDOMXPath,'evaluate')) $xp=isset($contextnode->myDOMNode) ? $this->myDOMXPath->evaluate($eval_str,$contextnode->myDOMNode) : $this->myDOMXPath->evaluate($eval_str);
-               else $xp=isset($contextnode->myDOMNode) ? $this->myDOMXPath->query($eval_str,$contextnode->myDOMNode) : $this->myDOMXPath->query($eval_str);
-               $xp=new php4DOMNodelist($xp,$this->myOwnerDocument);
-               return ($xp->type===XPATH_UNDEFINED) ? false : $xp;
-       }
-       function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);}
-}
-
-if (extension_loaded('xsl'))
-{//See also: http://alexandre.alapetite.fr/doc-alex/xslt-php4-php5/
-       function domxml_xslt_stylesheet($xslstring) {return new php4DomXsltStylesheet(DOMDocument::loadXML($xslstring));}
-       function domxml_xslt_stylesheet_doc($dom_document) {return new php4DomXsltStylesheet($dom_document);}
-       function domxml_xslt_stylesheet_file($xslfile) {return new php4DomXsltStylesheet(DOMDocument::load($xslfile));}
-       class php4DomXsltStylesheet
-       {
-               private $myxsltProcessor;
-               function php4DomXsltStylesheet($dom_document)
-               {
-                       $this->myxsltProcessor=new xsltProcessor();
-                       $this->myxsltProcessor->importStyleSheet($dom_document);
-               }
-               function process($dom_document,$xslt_parameters=array(),$param_is_xpath=false)
-               {
-                       foreach ($xslt_parameters as $param=>$value) $this->myxsltProcessor->setParameter('',$param,$value);
-                       $myphp4DOMDocument=new php4DOMDocument();
-                       $myphp4DOMDocument->myDOMNode=$this->myxsltProcessor->transformToDoc($dom_document->myDOMNode);
-                       return $myphp4DOMDocument;
-               }
-               function result_dump_file($dom_document,$filename)
-               {
-                       $html=$dom_document->myDOMNode->saveHTML();
-                       file_put_contents($filename,$html);
-                       return $html;
-               }
-               function result_dump_mem($dom_document) {return $dom_document->myDOMNode->saveHTML();}
-       }
-}
-?>
diff --git a/CAS/CAS/languages/catalan.php b/CAS/CAS/languages/catalan.php
deleted file mode 100644 (file)
index 3d67473..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/spanish.php\r
- * @author Iván-Benjamín García Torà <ivaniclixx AT gmail DOT com>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => 'usant servidor',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => 'Autentificació CAS necessària!',\r
- CAS_STR_LOGOUT \r
- => 'Sortida de CAS necessària!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click <a href="%s">aquí</a> per a continuar.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => 'Autentificació CAS fallida!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>No estàs autentificat.</p><p>Pots tornar a intentar-ho fent click <a href="%s">aquí</a>.</p><p>Si el problema persisteix hauría de contactar amb l\'<a href="mailto:%s">administrador d\'aquest llocc</a>.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => 'El servei `<b>%s</b>\' no està disponible (<b>%s</b>).'\r
-);\r
-\r
-?>\r
diff --git a/CAS/CAS/languages/english.php b/CAS/CAS/languages/english.php
deleted file mode 100644 (file)
index c143450..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/english.php\r
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => 'using server',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => 'CAS Authentication wanted!',\r
- CAS_STR_LOGOUT \r
- => 'CAS logout wanted!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => 'You should already have been redirected to the CAS server. Click <a href="%s">here</a> to continue.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => 'CAS Authentication failed!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>You were not authenticated.</p><p>You may submit your request again by clicking <a href="%s">here</a>.</p><p>If the problem persists, you may contact <a href="mailto:%s">the administrator of this site</a>.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => 'The service `<b>%s</b>\' is not available (<b>%s</b>).'\r
-);\r
-\r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/french.php b/CAS/CAS/languages/french.php
deleted file mode 100644 (file)
index b077ec0..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/english.php\r
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => 'utilisant le serveur',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => 'Authentication CAS n�cessaire&nbsp;!',\r
- CAS_STR_LOGOUT \r
- => 'D�connexion demand�e&nbsp;!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => 'Vous auriez du etre redirig�(e) vers le serveur CAS. Cliquez <a href="%s">ici</a> pour continuer.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => 'Authentification CAS infructueuse&nbsp;!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>Vous n\'avez pas �t� authentifi�(e).</p><p>Vous pouvez soumettre votre requete � nouveau en cliquant <a href="%s">ici</a>.</p><p>Si le probl�me persiste, vous pouvez contacter <a href="mailto:%s">l\'administrateur de ce site</a>.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => 'Le service `<b>%s</b>\' est indisponible (<b>%s</b>)'\r
-\r
-);\r
-\r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/german.php b/CAS/CAS/languages/german.php
deleted file mode 100644 (file)
index 29daeb3..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/german.php\r
- * @author Henrik Genssen <hg at mediafactory.de>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => 'via Server',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => 'CAS Authentifizierung erforderlich!',\r
- CAS_STR_LOGOUT \r
- => 'CAS Abmeldung!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => 'eigentlich h&auml;ten Sie zum CAS Server weitergeleitet werden sollen. Dr&uuml;cken Sie <a href="%s">hier</a> um fortzufahren.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => 'CAS Anmeldung fehlgeschlagen!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontkatieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => 'Der Dienst `<b>%s</b>\' ist nicht verf&uuml;gbar (<b>%s</b>).'\r
-);\r
-\r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/greek.php b/CAS/CAS/languages/greek.php
deleted file mode 100644 (file)
index fdff77e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/greek.php\r
- * @author Vangelis Haniotakis <haniotak at ucnet.uoc.gr>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => '��������������� � ������������',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => '���������� � ����������� CAS!',\r
- CAS_STR_LOGOUT \r
- => '���������� � ���������� ��� CAS!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => '�� ������ �� ������ �������������� ���� ����������� CAS. ����� ���� <a href="%s">���</a> ��� �� ����������.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => '� ����������� CAS �������!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>��� ���������������.</p><p>�������� �� ����������������, �������� ���� <a href="%s">���</a>.</p><p>��� �� �������� ���������, ����� �� ����� �� ��� <a href="mailto:%s">�����������</a>.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => '� �������� `<b>%s</b>\' ��� ����� ��������� (<b>%s</b>).'\r
-);\r
-\r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/japanese.php b/CAS/CAS/languages/japanese.php
deleted file mode 100644 (file)
index 76ebe77..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file languages/japanese.php
- * @author fnorif (fnorif@yahoo.co.jp)
- * 
- * Now Encoding is EUC-JP and LF
- **/
-
-$this->_strings = array(
- CAS_STR_USING_SERVER 
- => 'using server',
- CAS_STR_AUTHENTICATION_WANTED 
- => 'CAS�ˤ��ǧ�ڤ�Ԥ��ޤ�',
- CAS_STR_LOGOUT 
- => 'CAS����?�����Ȥ��ޤ�!',
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED 
- => 'CAS�����Ф˹Ԥ�ɬ�פ�����ޤ�����ưŪ��ž������ʤ����� <a href="%s">������</a> �򥯥�å�����³�Ԥ��ޤ���',
- CAS_STR_AUTHENTICATION_FAILED 
- => 'CAS�ˤ��ǧ�ڤ˼��Ԥ��ޤ���',
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED 
- => '<p>ǧ�ڤǤ��ޤ���Ǥ���.</p><p>�⤦���٥ꥯ�����Ȥ������������<a href="%s">������</a>�򥯥�å�.</p><p>���꤬��褷�ʤ����� <a href="mailto:%s">���Υ����Ȥδ����</a>���䤤��碌�Ƥ�������.</p>',
- CAS_STR_SERVICE_UNAVAILABLE
- => '�����ӥ� `<b>%s</b>\' �����ѤǤ��ޤ��� (<b>%s</b>).'
-);
-
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/languages.php b/CAS/CAS/languages/languages.php
deleted file mode 100644 (file)
index 2c6f8bb..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/languages.php\r
- * Internationalization constants\r
- * @author Pascal Aubry <pascal.aubry at univ-rennes1.fr>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-//@{\r
-/**\r
- * a phpCAS string index\r
- */\r
-define("CAS_STR_USING_SERVER",                1);\r
-define("CAS_STR_AUTHENTICATION_WANTED",       2);\r
-define("CAS_STR_LOGOUT",                      3);\r
-define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4);\r
-define("CAS_STR_AUTHENTICATION_FAILED",       5);\r
-define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED",  6);\r
-define("CAS_STR_SERVICE_UNAVAILABLE",         7);\r
-//@}\r
-\r
-?>
\ No newline at end of file
diff --git a/CAS/CAS/languages/spanish.php b/CAS/CAS/languages/spanish.php
deleted file mode 100644 (file)
index 3a8ffc2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php\r
-\r
-/**\r
- * @file languages/spanish.php\r
- * @author Iván-Benjamín García Torà <ivaniclixx AT gmail DOT com>\r
- * @sa @link internalLang Internationalization @endlink\r
- * @ingroup internalLang\r
- */\r
-\r
-$this->_strings = array(\r
- CAS_STR_USING_SERVER \r
- => 'usando servidor',\r
- CAS_STR_AUTHENTICATION_WANTED \r
- => '¡Autentificación CAS necesaria!',\r
- CAS_STR_LOGOUT \r
- => '¡Salida CAS necesaria!',\r
- CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED \r
- => 'Ya debería haber sido redireccionado al servidor CAS. Haga click <a href="%s">aquí</a> para continuar.',\r
- CAS_STR_AUTHENTICATION_FAILED \r
- => '¡Autentificación CAS fallida!',\r
- CAS_STR_YOU_WERE_NOT_AUTHENTICATED \r
- => '<p>No estás autentificado.</p><p>Puedes volver a intentarlo haciendo click <a href="%s">aquí</a>.</p><p>Si el problema persiste debería contactar con el <a href="mailto:%s">administrador de este sitio</a>.</p>',\r
- CAS_STR_SERVICE_UNAVAILABLE\r
- => 'El servicio `<b>%s</b>\' no está disponible (<b>%s</b>).'\r
-);\r
-\r
-?>\r
diff --git a/CAS/LICENSE b/CAS/LICENSE
new file mode 100644 (file)
index 0000000..261eeb9
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/CAS/NOTICE b/CAS/NOTICE
new file mode 100644 (file)
index 0000000..2b45649
--- /dev/null
@@ -0,0 +1,81 @@
+Copyright 2007-2011, JA-SIG, Inc.
+This project includes software developed by Jasig.
+http://www.jasig.org/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+===========================================================================
+
+Copyright © 2003-2007, The ESUP-Portail consortium
+
+Requirements for sources originally licensed under the New BSD License:
+
+Redistribution and use in source and binary forms, with or without 
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+- Neither the name of JA-SIG, Inc. nor the names of its contributors may be
+used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+===========================================================================
+
+Copyright (c) 2009, Regents of the University of Nebraska
+All rights reserved.
+
+Requirements for CAS_Autloader originally licensed under the New BSD License:
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list
+of conditions and the following disclaimer.
+
+Redistributions in binary form must reproduce the above copyright notice, this 
+list of conditions and the following disclaimer in the documentation and/or 
+other materials provided with the distribution.
+
+Neither the name of the University of Nebraska nor the names of its contributors
+may be used to endorse or promote products derived from this software without 
+specific prior written permission. 
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/CAS/README.md b/CAS/README.md
new file mode 100644 (file)
index 0000000..41afcd6
--- /dev/null
@@ -0,0 +1,28 @@
+phpCAS
+=======
+
+phpCAS is an authentication library that allows PHP applications to easily authenticate
+users via a Central Authentication Service (CAS) server.
+
+Please see the phpCAS website for more information:
+
+https://wiki.jasig.org/display/CASC/phpCAS
+
+LICENSE
+-------
+
+Copyright 2007-2011, JA-SIG, Inc.
+This project includes software developed by Jasig.
+http://www.jasig.org/
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this software except in compliance with the License.
+You may obtain a copy of the License at:
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/CAS/docs/Building b/CAS/docs/Building
new file mode 100644 (file)
index 0000000..a00e19c
--- /dev/null
@@ -0,0 +1,34 @@
+######################################## 
+### Build process for phpCAS package ###
+########################################
+
+1. Prepare your own build config:
+
+go to the utils/ dir and copy build-example.properties to a 
+build.properties file and adjust the path for all needed binaries. You need
+at least php and doxygen for package creation. Git is needed as a developer with
+commit priviledges and upload right for the distribution package.
+
+2. Install necessary php packages:
+
+Install the pear package PEAR_PackageFileManager2 via the command
+
+"pear install PEAR_PackageFileManager2"
+
+
+3. Run the "ant" tasks to build the phpCAS package and other developer tasks:
+
+ant dist      # create a local package
+ant clean     # clear local packages and temporary files
+ant prepare   # The default action, tags, packages, and commits to the local git repository
+ant push      # Push the new commits and tags to the origin repository (github)
+ant upload    # Upload to jasig
+ant makeCurrentSymlink # Set the symbolic link on the jasig site for the most current packages
+ant revert    # To revert any "ant prepare" actions before they are pushed to the github repo
+
+The ant prepare target is equivalent to ant tag && ant dist && ant markdev.
+
+To revert the commits and tag additions added in the ant tag and ant markdev
+targets, use the new ant revert target. This should not be done after pushing.
+Running ant prepare is safe and can be followed by ant revert to get rid of the
+added commits and tag in your local repository.
\ No newline at end of file
diff --git a/CAS/docs/ChangeLog b/CAS/docs/ChangeLog
new file mode 100644 (file)
index 0000000..a71ff54
--- /dev/null
@@ -0,0 +1,511 @@
+Changes in version 1.3.2
+Security Fixes:
+   * CVE-2012-5583 Missing CN validation of CAS server certificate [#58] (Joachim Fritschi)
+
+Bug Fixes:
+   * Fix broken character encoding in Greek and French [#40] (Joachim Fritschi)
+   * Minor error corrections in a few example files [] (Joachim Fritschi)
+   * Remove erroneous break statement [#44] (jbittel)
+   * Use X-Forwarded-Port [#45] (Andrew Kirkpatrick)
+   * Stop autoloader using set_include_path [#51/#52] (drysdaleb)
+   * Fix undefined property in the rebroadcast code [#47] (Joachim Fritschi)
+
+Improvement:
+   * Enable getCookies on a proxied sevices [#56] (Adam Franco)
+Changes in version 1.3.1
+Bug Fixes:
+   * Readd PEAR support to the package [#30]  (Joachim Fritschi)
+   * fix a __autoload conflicts in the autoloader [#36] (Joachim Fritschi)
+   * fix PEAR code style errors [25] (Joachim Fritschi)
+   * properly unset variables during checkAuthenticate[#35] (Joachim Fritschi)
+
+Changes in version 1.3.0
+Improvements:
+   * enable single sign-out when session has already started [#29] (Benvii)
+
+Changes in version 1.3.0RC1
+
+Bug Fixes:
+   * the saml logout url should be parsed urlencoded [#24] (dlineate)
+   * fix a proxy mode bug introduced in a previous comitt [#16] (Adam Franco)
+   * Fix include_path order so that the phpCAS path takes precedence [#13] (Adam Franco)
+   * fix invalid characters in the php session naming [#17] (Joachim Fritschi)
+   * fix an initialisation problem introduced in the PGT storage [18] (Daniel Frett)
+   * make sure the PGTStorage object is initialized if a user is utilizing the createTable method [#4] (Daniel Frett)
+   * Fix error message in phpCAS::setCacheTimesForAuthRecheck() [PHPCAS-132/#1] (Bradley Froehle)
+   * Always return attributes in utf8 [PHPCAS-102]
+   * Fix warning during debugging if debug is set to false [PHPCAS-123] (Sean Watkins)
+
+New Features:
+    * Add a script to create the PGT db table in proxy mode [#11] (Joachim Fritschi)
+    * Switch to the Apache License [#5] (Adam Franco, Joachim Fritschi)
+    * Move to github and add all necessary file to package [#12] (Adam Franco)
+    * New build process for github [#12] (Adam Franco)
+    * Update unit tests to work with the lastest phpunit version [PHPCAS-128] (Adam Franco)
+    * Refacatoring of the protocol decision making to allow validation of proxied usage [PHPCAS-69] (Joachim Fritschi, Adam Franco)
+    * Rebroadcast of logout and pgtiou to support clustered phpcas [PHPCAS-100] (Matthew Selwood, Adam Franco)
+
+Improvements:
+    * Improved cookie handling [] (Adam Franco
+    * Indent, format and user name guidelines of PEAR [#14] (Joachim Fritschi)
+    * Add a class autoloading feature [PHPCAS-125/#8] (Joachim Fritschi)
+    * Remove global variables [PHPCAS-126] (Adam Franco)
+    * Implementation of an exception framework to allow gracefull termination [PHPCAS-109] (Joachim Fritschi)
+    
+Security Fixes:
+    * CVE-2012-1104 validate proxied usage of a service [PHPCAS-69] (Joachim Fritschi, Adam Franco)
+    * CVE-2012-1105 change the default PGT save path to the session storage path and set proper permissions [#22] (Joachim Fritschi)
+
+Changes in version 1.2.2
+
+Bug Fixes:
+    * Improve compatibility with php < 5.3 for E_USER_DEPRECATED [PHPCAS-116] (Hugh Eaves)
+
+Changes in version 1.2.2RC1
+
+Bug Fixes:
+    * CASClient::getURL() cannot be private [PHPCAS-103] (Joachim Fritschi)
+    * CASClient::getServerServiceValidateURL() doesn't respect existing query strings [PHPCAS-104] (Bradley Froehle, Joachim Fritschi)
+    * CASClient::retrievePT() must be a public function [PHPCAS-107] (Joachim Fritschi)
+    * Expose setNoClearTicketsFromUrl() to the client [PHPCAS-108]  (Joachim Fritschi)
+    * Remove the PGT filestorage in xml format that is not implemented [PHPCAS-112] (Joachim Fritschi)
+    * Fix compatibility of the PGT db storage interface with postgres [PHPCAS-113] (Joachim Fritschi)
+
+Improvement
+    * Support for proxied POST requests. [PHPCAS-90] (Adam Franco)
+    * Add missing example for the new pgt-db storage [PHPCAS-101] (Joachim Fritschi)
+    * CASClient::getServerLoginURL(): Don't cache gateway/renew parameters [PHPCAS-105] (Bradley Froehle)
+    * fix parsing of cookies with special symbols in their values [PHPCAS-106] (Joachim Fritschi)
+    * Removal of the debug_backtrace hack for php4 [PHPCAS-110] (Joachim Fritschi)
+    * Clean up the naming structure of the classes [PHPCAS-111] (Joachim Fritschi)
+    * Better debug log output format [PHPCAS-114] (Joachim Fritschi)
+    * Many more examples and one central config. Improved code documentation [PHPCAS-86] (Joachim Fritschi, Adam Franco)
+
+Changes in version 1.2.1
+   * None
+
+Changes in version 1.2.1RC1
+Improvements
+   * add support for storing PGTs in a database [PHPCAS-94] (Daniel Frett)
+    
+Bug Fixes
+   * phpCAS::setDebug(FALSE) should stop logging [PHPCAS-95] (Joachim Fritschi)
+   * fix checkAuthenticate return value documentation [PHPCAS-92] (Joachim Fritschi)
+   * fix PGTStorage contructor name [PHPCAS-93] (Daniel Frett)
+   * fix the PHPCAS_SERVICE_NOT_AVAILABLE constant [PHPCAS-91] (Daniel Frett)
+   * fix redirection with multiple proxies in HTTP_X_FORWARDED_HOST [PHPCAS-98] (Joachim Fritschi)
+   * fix some undefinde variable warnings in debug mode [PHPCAS-96] (Joachim Fritschi)
+
+Changes in version 1.2.0
+   * None
+   
+Changes in version 1.2.0RC2
+Improvements
+   * add callback hooks during authentication and single sign-out [PHPCAS-76] (Adam Franco)
+
+Changes in version 1.2.0RC1
+Improvements
+   * add hasAttribute($key) and getAttribute($key) [PHPCAS-43] (Adam Franco)
+   * add unit tests for cas 2.0 attribute support [PHPCAS-88] (Adam Franco)
+   * expose the proxy chain through the phpcas interface [PHPCAS-89] (Adam Franco)
+   * add deprecation messages to the logout functions with an url parameter [PHPCAS-85] (Joachim Fritschi)
+
+Bug Fixes
+       * fix  public/private modifier for some functions [PHPCAS-87] (Joachim Fritschi)
+
+Changes in version 1.2.0-beta1
+
+Bug Fixes
+  * fix redirection behind a proxy. [PHPCAS-78] (Alex Barker)
+  * remove the bogus setCasServerCert() function and clean up the curl ssl settings [PHPCAS-84] (Joachim Fritschi)
+  
+Improvements
+   * mark the logout functions with an url parameter a deprecated [PHPCAS-85] (Joachim Fritschi)
+   * add public/private modifier for all vars and functions [PHPCAS-77] (Joachim Fritschi)
+   * add a testing framwork that implement on and offline testing capabilities [PHPCAS-66] (Adam Franco)
+   * add RFC compliant cookie storage for the proxy() mode. [PHPCAS-54] (Adam Franco)
+   * removal of the domxml compatibility lib [PHPCAS-72] (Matthew Brooks, Joachim Fritschi)
+   * add support for attributes for the cas_2.0 protocol [PHPCAS-43] (Joachim Fritschi, Adam Franco)
+   * removal of unused code and comments [PHPCAS-63] (Joachim Fritschi)
+   * fix static function warnings for php 5.x [PHPCAS-46] (Joachim Fritschi)
+   
+Changes in version 1.1.3
+  Bug Fixes
+   * removal of the non functional pgt-db backend [PHPCAS-65] (Joachim Fritschi)
+
+Changes in version 1.1.3RC1
+ Security Issue
+    * CVE-2010-3690 phpCAS: XSS during a proxy callback [PHPCAS-80] (Joachim Fritschi)
+    * CVE-2010-3691 phpCAS: prevent symlink attacks during a proxy callback [PHPCAS-80] (Joachim Fritschi)
+    * CVE-2010-3692 phpCAS: directory traversal during a proxy callback [PHPCAS-80] (Joachim Fritschi)
+
+ Bug Fixes
+   * fix missing $this in domxml-php4-to-php5 [PHPCAS-73] (Iñaki Arenaza)
+   * fix broken redirection with safari [PHPCAS-79] (Alex Barker)
+   * fix missing exit() call during ticket validation [PHPCAS-76] (Igor Blanco,Joachim Fritschi)
+   * fix a notice because REQUEST_URL is not defined on IIS [PHPCAS-81] (Iñaki Arenaza)
+   * fix a typo in pgt-db.php [PHPCAS-75] (Julien Cochennec)
+ Improvements
+   * upgrade domxml-php4-to-php5 to the newest version [PHPCAS-74] (Joachim Fritschi)
+
+Changes in version 1.1.2
+   * None
+   
+Changes in version 1.1.2RC2
+ Bug Fixes
+    * Prevent domxml-php4-to-php5 to be inclueded twice [PHPCAS-48] (Brad Krane)
+
+Changes in version 1.1.2RC1
+Security Issue
+    * Fix a session hijacking hole CVE-2010-2795 [PHPCAS-61] (Joachim Fritschi)
+    * callbackurl in proxy mode should be urlencoded CVE-2010-2796 [PHPCAS-67] (Joachim Fritschi)
+
+ Improvement
+    * Debuglog contains phpCAS version information [PHPCAS-62] (Joachim Fritschi)
+    
+ Bug Fixes   
+    * Fix warnings for SAML responses without attributes [PHPCAS-59] (Joachim Fritschi)
+    * Fix duplicate SAML debug output [PHPCAS-64] (Joachim Fritschi)
+    * Providing a new ST/PT/SA during an authenticated session will be ignored 
+      and a warning will be issued to the debug log. [PHPCAS-61] (Joachim Fritschi)
+    * fix 2 undefinded variable notices in serviceWeb() [PHPCAS-68] (Joachim Fritschi)
+
+Changes in version 1.1.1
+Improvement
+    * On Single Sign Out destroy any existing application session before deleting the phpcas session [PHPCAS-58] (Joachim Fritschi)
+    
+Changes in version 1.1.1RC2
+Bug fixes
+    * Fix bug in handling urls containing parameters without values [PHPCAS-57] (Joe Lencioni)
+    * New XSS patch for PHPCAS-52 that was undone in r48507 [PHPCAS-57] (Joachim Fritschi)
+
+Changes in version 1.1.1RC1
+Bug fixes
+    * Fix bug in restoring an existing session [PHPCAS-55] (Joachim Fritschi)
+    
+Changes in version 1.1.0
+Improvement
+    * Replace deprecated split() with explode(). [PHPCAS-42] (Joe Lencioni)
+
+Changes in version 1.1.0RC8
+Bug fixes
+    * Add additional comments regarding the use of serviceValidate and proxyValdiate [PHPCAS-44] (Joachim Fritschi)
+    * Revert all changes made to the ticket parsing in r47347 r48210 [PHPCAS-44] (Joachim Fritschi)
+    * Fix warning when destroying uninitialized session [PHPCAS-53] (Yann Richard,Joachim Fritschi)
+
+Changes in version 1.1.0RC7
+Security fixes
+    * Fix XSS Vulnerability. Sanatize parameters before using the url submitted by a client [PHPCAS-52] (Joachim Fritschi)
+    
+Changes in version 1.1.0RC6
+Bug fixes
+    * restore any possible old session before renaming the session [PHPCAS-50] (Joachim Fritschi)
+
+Changes in version 1.1.0RC5
+Bug fixes
+    * fixed don't destroy existing sessions unless needed, more debug output [PHPCAS-50] (Joachim Fritschi)
+
+Changes in version 1.1.0RC4
+Bug fixes
+
+    * fixed use PHP4 functions to parse saml11 attributes [PHPCAS-51] (Joachim Fritschi)
+
+Changes in version 1.1.0RC3
+Bug fixes
+
+    * added a check for missing params [PHPCAS-42] (Joachim Fritschi)
+
+Changes in version 1.1.0RC2
+New features
+
+    * added custom validation Urls [PHPCAS-45] (Joachim Fritschi).
+
+Bug fixes
+
+    * fixed PGT DB storage parameter list [PHPCAS-47] (Paul Merchant, Jr.)
+    * fixed parsing of STs [PHPCAS-44] (Joachim Fritschi)
+    * fixed session initialisation [PHPCAS-50] (Joachim Fritschi)
+    * fixed urls with than one query parameter [PHPCAS-42] (Caio Chassot)
+
+Changes in version 1.1.0RC1
+New features
+
+    * added SAML support [PHPCAS-40] (Brian Long and Matthias Crauwels).
+
+Bug fixes
+
+    * fixed invalid validation URLs [PHPCAS-39] (Alex Danieli).
+    * removed old PHP4 references [PHPCAS-41] (Yann Richard).
+    * fixed curl options [PHPCAS-38] (Andy Cowling).
+
+Improvement
+
+    * added accept IP addresses for allowed clients [PHPCAS-37] (Arunas Stockus) 
+
+Changes in version 1.0.2RC1
+Bug fixes
+
+    * fix redirections masking error messages [PHPCAS-36] (Olivier Berger)      
+    * fixed validatePGT() failing on phpCAS::traceBegin() with newer domxml-php4-to-php5.php [PHPCAS-35] (Olivier Berger)       
+    * Fixed missing exit() at end of callback() method [PHPCAS-34] (Olivier Berger)
+    * Update included domxml-php4-php5.php to most recent version now under LGPL [PHPCAS-30] (Olivier Berger)    
+    * fixed empty $target_service in CAS_Client:serviceMail [PHPCAS-22] (Julien Marchal).
+
+Changes in version 1.0.1
+Bug fixes
+
+    * fixed PEAR base install directory [PHPCAS-28] (Brett Bieber).
+    * fixed illegal characters in session id [PHPCAS-29] (Michael Ströder, Brett Bieber).
+    * fixed refresh with ticket causes authentication failure [related to PHPCAS-27] (Brett Bieber).
+    * fixed conflict with custom session handlers [PHPCAS-26] (Martin Gonzalez).
+
+Changes in version 1.0.0
+New features
+
+    * phpCAS is now PEAR-installable (Brett Bieber).
+    * added method handleLogoutRequests() to handle logout requests incoming from the CAS server (Julien Marchal and Pascal Aubry, requested by Craig Andrews).
+    * added methods setHttpProxy(), setNetworkInterface() and setExtraCurlOptions() (Stéphane Gully).
+
+Enhancements
+
+    * removed undesirable notice (Glennie Vignarajah).
+    * removed PEAR DB dependency when storing PGTs to the filesytem (Stéphane Gully).
+
+Changes in version 0.6.0
+New features
+
+    * added methods setCasServerCert() and setCasServerCaCert() to authenticate the CAS server, and method setNoCasServerValidation() to skip the SSL checks (Pascal Aubry, requested by Andrew Petro).
+    * Added spanish and catalan translations (Ivan Garcia).
+
+Bug fix
+
+    * fixed PGT storage path on Windows (Olivier Thebault).
+
+Changes in version 0.5.1
+New features
+
+    * restored method isAuthenticated() (Julien Marchal).
+
+Changes in version 0.5.0
+New features
+
+    * added japanese translation (Noriyuki Fukuoka).
+    * added german translation (Henrik Genssen).
+    * phpCAS now works for CAS v3 proxy tickets (Matt Zukowski).
+    * phpCAS now also works with lighttpd (Marvin Addison)
+
+Bug fixes
+
+    * fixed method setHTMLFooter() (Noriyuki Fukuoka).
+    * fixed method setHTMLHeader() (Xavier Castanho).
+    * fixed method isHttps() (Henrik Genssen).
+    * fixed method PGTStorageDB() (Ray Lambe).
+    * encode all the parameters, not only '&' characters (Matthew Debus).
+    * fixed ST proxy tickets (Julien Marchal).
+
+Changes in version 0.4.23
+Enhancement
+
+    * removed notice messages (David Lowry).
+
+Changes in version 0.4.22
+Bug fix
+
+    * added default value for parameter gateway in methods setServerLoginUrl() and redirectToCas() (Velpi).
+
+New Feature
+
+    * added method isSessionAuthenticated() (Brendan Arnold).
+
+Other change
+
+    * removed the call to error_reporting() to allow the configuration of error reporting at server level (Pascal Aubry, requested by Sylvain Derosiaux).
+
+Changes in version 0.4.21
+Bug fix
+
+    * some URLs were ill-formed in some rare circumstances (Jérôme Andrieux).
+
+New Feature
+
+    * added methods setServerLoginURL() and setServerLogoutURL() (Wyman Chan).
+
+Changes in version 0.4.20
+New feature
+
+    * phpCAS::checkAuthentication() implements the gateway feature of CAS (Pascal Aubry, requested by Romuald Lorthioir).
+
+Other change
+
+    * phpCAS::authenticateIfNeeded() was renamed phpCAS::forceAuthentication() (Pascal Aubry).
+
+Changes in version 0.4.19
+New features
+
+    * the service URL for the CAs server can be fixed with method phpCAS::setFixedServiceURL (Julien Marchal).
+    * the callback URL used to receive PGTs can be fixed with method phpCAS::setFixedCallbackURL() (Julien Marchal).
+
+    * added a CAS_Client wrapper to class phpCAS for method retrievePGT() (Julien Marchal).
+
+Changes in version 0.4.18
+Bug fixes
+
+    * debugging information was missing (Alexandre Boisseau).
+    * used an undefined variable in pgt-file.php (Alexandre Boisseau).
+
+Changes in version 0.4.17
+Enhancement
+
+    * made phpCAS PHP5 compliant (Vangelis Haniotakis).
+
+Changes in version 0.4.16
+Enhancement
+
+    * added the possibility not to start the session management (Vangelis Haniotakis).
+
+Changes in version 0.4.15
+Enhancement
+
+    * added a hack to make phpCAS work with IIS (Vangelis Haniotakis).
+
+Changes in version 0.4.14
+Enhancement
+
+    * a URL can be given to the CAS server on logout (Sébastien Gougeon and Yann Richard).
+
+Changes in version 0.4.13
+Bug fix
+
+    * Removed infinite loop in debug mode (Robert Legros).
+
+Changes in version 0.4.12
+Enhancement
+
+    * phpCAS now works even if the web server does not set SERVER_NAME, by relying on HTTP_HOST (Terence Chiu).
+
+Changes in version 0.4.11
+Bug fix
+
+    * A typo prevented ticket validation to work correctly (Robert Legros).
+
+Changes in version 0.4.10
+Enhancement
+
+    * phpCAS was previously working with PHP >= 4.3.0. A debug_backtrace() wrapper was added and get_elements_by_tagname() calls were modified to make phpCAS work with phpCAS >= 4.2.2 (Robert Legros).
+
+Changes in version 0.4.9
+New features
+
+    * Added greek translation (Haniotakis Vangelis).
+
+Changes in version 0.4.8
+Enhancements
+
+    * PEAR's DB.php inclusion is done only if a DB class was not already included. This eases the integration into some stand-alone tools that already include DB.php, like Tikiwiki (Pascal Aubry, requested by Terence Chiu).
+
+Changes in version 0.4.7
+Enhancements
+
+    * PHP session is now destroyed when using the phpCAS::logout() method (Pascal Aubry, requested by Ruben Recaba).
+    * Call getenv() whenever possible instead of directly dealing with environment variables (with $_ENV['xxx']), as $_ENV is not available par default on some Windows systems (Pascal Aubry).
+    * Set error reporting level to E_ALL ~ E_NOTICE (Pascal Aubry).
+    * Added the release number in the name of the main directory of the zip distribution file (Pascal Aubry, requested by Vincent Mathieu).
+    * Explicitly set certificate control to get round with different curl default configurations (Wyman Chan).
+
+Changes in version 0.4.6
+Security bug fix
+
+    * Credentials given to HTTP realms were given in the service URLs to the CAS server (Julien Marchal).
+
+Enhancements
+
+    * phpCAS now works behind an Apache reverse proxy (Julien Marchal).
+
+Changes in version 0.4.5
+Enhancements
+
+    * Developer releasing is now made by ant (Pascal Aubry).
+
+Bug fixes
+
+    * CAS/PGTStorage files have been renamed to fit to Windows case insensitivity (Pascal Aubry);
+    * %TMP% and %TEMP% environment variables are now taken into account to set the location of the log file (Pascal Aubry).
+
+Changes in version 0.4.4
+Enhancement
+
+    * ticket retrieval and validation is now made with curl (Pascal Aubry).
+
+Changes in version 0.4.3
+Bug fix
+
+    * phpCAS was not exiting right after redirecting in callback mode (Julien Marchal)
+
+Changes in version 0.4.2
+New features
+
+    * Authentication checking is not necessarily redirecting to the CAS server (introduced phpCAS::isAuthenticated()) (Pascal Aubry)
+    * phpCAS can now be used to access IMAP/POP3/NNTP services (cf phpCAS::serviceMail()) (Pascal Aubry)
+
+Enhancements
+
+    * debugging informations has been improved and is now send to a separate file (/tmp/phpCAS.log by default, can be changed by phpCAS::setDebug()) (Pascal Aubry)
+
+Changes
+
+    * phpCAS::authenticate() is replaced by phpCAS::authenticateIfNeeded() (semantics unchanged) (Pascal Aubry)
+    * phpCAS::service() is replaced by phpCAS::serviceWeb() (semantics unchanged) (Pascal Aubry)
+    * phpCAS::setDebug() accepts FALSE (to stop debugging) or the name of a file (to log informations) (Pascal Aubry)
+
+Changes in version 0.4.1
+New features
+
+    * Sessionning between CAS proxies and services (Pascal Aubry)
+
+Changes in version 0.4
+New features
+
+    * CAS proxies can be chained (Pascal Aubry)
+    * improved error printing and debugging (introduced phpCAS::error()) (Pascal Aubry)
+
+Enhancements
+
+    * proxy parameter removed from phpCAS::client() and introduced phpCAS::proxy() (Pascal Aubry)
+    * moved history from CAS/doc.php to history.php (create_version script updated accordingly) (Pascal Aubry)
+    * improved type-checking and controls for phpCAS methods (Pascal Aubry)
+
+Changes in version 0.3.2
+New features
+
+    * CAS proxies now work with HTTP (HTTPS only used for callbacks) (Pascal Aubry)
+
+Changes in version 0.3.1
+Bug fixes
+
+    * syntax error in CAS/Client.php (Julien Marchal)
+
+Changes in version 0.3
+New features
+
+    * CAS proxies are now supported (but no PGT retrieving for proxied client) (Pascal Aubry)
+    * introduced phpCAS container (Pascal Aubry)
+
+Bug fixes
+
+    * CAS_LANG_DEFAULT is now taken into account (Pascal Aubry)
+
+TODO
+
+    * support for PGT storage to databases (Pascal Aubry)
+    * PGT retrieving for proxied clients (Pascal Aubry)
+
+Version 0.2
+Features (Pascal Aubry)
+
+    * `Basic' (1.0) CAS mechanism supported (CAS proxies not implemented)
+    * Support for CAS versions 1.0 and 2.0 URL's
+    * Debug mode
+    * Customization of all output pages
+    * Internationalization (english and french, looking for translators...)
diff --git a/CAS/docs/Upgrading b/CAS/docs/Upgrading
new file mode 100644 (file)
index 0000000..2f1bd36
--- /dev/null
@@ -0,0 +1,100 @@
+################################
+### Upgrading 1.3.1 -> 1.3.2 ###
+################################
+
+Due to the missing validation of the CN of the SSL certifcate it may be that
+phpcas fails validation of CAS server certicates that do not match the IP/DNS 
+name you use in the phpcas client() or proxy() setup.
+If this happens a quick workaround to change the setup to the old but unsecure
+behaviour. This can be seen in the no_ssl_cn_validation example.
+This is not a recommended setting and is no a secure setup!
+
+################################
+### Upgrading 1.2.x -> 1.3.0 ###
+################################
+
+
+------------------------------------------------------------------
+1. Changing of the default debug.log permissions:
+------------------------------------------------------------------
+
+The default debug log is now created with 0600 permissions to be only readable
+by the webserver
+
+-------------------------------------------------------
+2. Changing of the behaviour of proxied applications:
+-------------------------------------------------------
+
+If your application is being proxied (Another casified application is using
+proxy tickets to access your service you need to change your configuration. The
+new default configuration is now to deny any proxied use of your service unless
+it is exlicitly allowed:
+
+If you want your service to be proxied you have to enable it (default disabled) 
+and define an accepable list of proxies that are allowed to proxy your service.
+
+Add each allowed proxy definition object. For the normal CAS_ProxyChain
+class, the constructor takes an array of proxies to match. The list is in
+reverse just as seen from the service. Proxies have to be defined in reverse
+from the service to the user. If a user hits service A and gets proxied via
+B to service C the list of acceptable on C would be array(B,A). The definition
+of an individual proxy can be either a string or a regexp (preg_match is used)
+that will be matched against the proxy list supplied by the cas server
+when validating the proxy tickets. The strings are compared starting from
+the beginning and must fully match with the proxies in the list.
+
+Examples:
+      phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+              'https://app.example.com/'
+          )));
+or
+      phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+              '/^https:\/\/app[0-9]\.example\.com\/rest\//',
+              'http://client.example.com/'
+          )));
+
+For quick testing or in certain production screnarios you might want to
+allow allow any other valid service to proxy your service. To do so, add
+the "Any" chain:
+
+      phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+
+THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+ IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+ ON THIS SERVICE.
+
+
+----------------------------------------------------------------
+3. Changing of the default PGT file storage location in proxy mode:
+----------------------------------------------------------------
+
+The default storage of the sensitive PGT session files is the 
+session_save_path() now. This is a php environment dependent dir which is also
+used for storing your php session data. The default permissions are also changed
+to 0600 to be only readable by the webserver.
+
+
+
+
+------------------------------------------------------------------
+4. The setPGTStorageFile() function has changed it parameters.
+------------------------------------------------------------------
+
+The setPGTStorageFile() function no longer needs an storage "format" argument.
+Since the format functionality was never implemented it has now been dropped 
+and only the path argument is necessary.
+
+------------------------------------------------------------------
+5. The startSession boolean in the constructor has been changed to
+changeSessionID
+------------------------------------------------------------------
+
+The last parameter of the constructor for has been changed from "start session"
+to "change session ID". This has no negative effects on existion integrations
+but will allow integration with other frameworks to take advantage of single 
+sign-out if they switch to "true". phpCAS will then rename the session id 
+(keeping all vars) and be able to single sign-out users.
+
+
+
+
diff --git a/CAS/docs/examples/config.example.php b/CAS/docs/examples/config.example.php
new file mode 100644 (file)
index 0000000..3231e95
--- /dev/null
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * The purpose of this central config file is configuring all examples
+ * in one place with minimal work for your working environment
+ * Just configure all the items in this config according to your environment
+ * and rename the file to config.php
+ *
+ * PHP Version 5
+ *
+ * @file     config.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+$phpcas_path = '../../source/';
+
+///////////////////////////////////////
+// Basic Config of the phpCAS client //
+///////////////////////////////////////
+
+// Full Hostname of your CAS Server
+$cas_host = 'cas.example.com';
+
+// Context of the CAS Server
+$cas_context = '/cas';
+
+// Port of your CAS server. Normally for a https server it's 443
+$cas_port = 443;
+
+// Path to the ca chain that issued the cas server certificate
+$cas_server_ca_cert_path = '/path/to/cachain.pem';
+
+//////////////////////////////////////////
+// Advanced Config for special purposes //
+//////////////////////////////////////////
+
+// The "real" hosts of clustered cas server that send SAML logout messages
+// Assumes the cas server is load balanced across multiple hosts
+$cas_real_hosts = array('cas-real-1.example.com', 'cas-real-2.example.com');
+
+// Database config for PGT Storage
+$db = 'pgsql:host=localhost;dbname=phpcas';
+//$db = 'mysql:host=localhost;dbname=phpcas';
+$db_user = 'phpcasuser';
+$db_password = 'mysupersecretpass';
+$db_table = 'phpcastabel';
+$driver_options = '';
+
+///////////////////////////////////////////
+// End Configuration -- Don't edit below //
+///////////////////////////////////////////
+
+// Generating the URLS for the local cas example services for proxy testing
+if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
+    $curbase = 'https://' . $_SERVER['SERVER_NAME'];
+} else {
+    $curbase = 'http://' . $_SERVER['SERVER_NAME'];
+}
+if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
+    $curbase .= ':' . $_SERVER['SERVER_PORT'];
+}
+
+$curdir = dirname($_SERVER['REQUEST_URI']) . "/";
+
+// CAS client nodes for rebroadcasting pgtIou/pgtId and logoutRequest
+$rebroadcast_node_1 = 'http://cas-client-1.example.com';
+$rebroadcast_node_2 = 'http://cas-client-2.example.com';
+
+// access to a single service
+$serviceUrl = $curbase . $curdir . 'example_service.php';
+// access to a second service
+$serviceUrl2 = $curbase . $curdir . 'example_service_that_proxies.php';
+
+$pgtBase = preg_quote(preg_replace('/^http:/', 'https:', $curbase . $curdir), '/');
+$pgtUrlRegexp = '/^' . $pgtBase . '.*$/';
+
+$cas_url = 'https://' . $cas_host;
+if ($cas_port != '443') {
+    $cas_url = $cas_url . ':' . $cas_port;
+}
+$cas_url = $cas_url . $cas_context;
+
+// Set the session-name to be unique to the current script so that the client script
+// doesn't share its session with a proxied script.
+// This is just useful when running the example code, but not normally.
+session_name(
+    'session_for:'
+    . preg_replace('/[^a-z0-9-]/i', '_', basename($_SERVER['SCRIPT_NAME']))
+);
+// Set an UTF-8 encoding header for internation characters (User attributes)
+header('Content-Type: text/html; charset=utf-8');
+?>
diff --git a/CAS/docs/examples/create_pgt_storage_db_table.php b/CAS/docs/examples/create_pgt_storage_db_table.php
new file mode 100644 (file)
index 0000000..11cc7a0
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ *  Script that generates a default table for PGT/PGTiou storage. This script
+ *  assumes a database with proper permissions exists and we are habe
+ *  permissions to create a table.
+ *  All database settings have to be set in the config.php file. Or the
+ *  CAS_PGTStorage_Db() options:
+ *  $db, $db_user, $db_password, $db_table, $driver_options
+ *  have to filled out directly. Option examples can be found in the
+ *  config.example.php
+ *
+ * PHP Version 5
+ *
+ * @file     create_pgt_storage_table.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+
+// Dummy client because we need a 'client' object
+$client = new CAS_Client(CAS_VERSION_2_0, true, $cas_host, $cas_port, $cas_context, false);
+
+// Set the torage object
+$cas_obj = new CAS_PGTStorage_Db($client, $db, $db_user, $db_password, $db_table, $driver_options);
+$cas_obj->init();
+$cas_obj->createTable();
+?>
+<html>
+  <head>
+    <title>phpCAS PGT db storage table creation</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+<body>
+<div class="success">
+<?php
+echo 'Table <b>' . $db_table . '</b> successfully created in database <b>' . $db . '</b>';
+?>
+</div>
+</body>
+</html>
\ No newline at end of file
diff --git a/CAS/docs/examples/example.css b/CAS/docs/examples/example.css
new file mode 100644 (file)
index 0000000..bf7f6c4
--- /dev/null
@@ -0,0 +1,10 @@
+.error {
+       border: 1px solid #aa0000;
+       color: #aa0000;
+       padding: 5px;
+}
+.success {
+       border: 1px solid #00aa00;
+       color: #00aa00;
+       padding: 5px;
+}
\ No newline at end of file
diff --git a/CAS/docs/examples/example_advanced_saml11.php b/CAS/docs/examples/example_advanced_saml11.php
new file mode 100644 (file)
index 0000000..0efdd8c
--- /dev/null
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * Advanced example for SAML with attributes and single logout
+ *
+ * PHP Version 5
+ *
+ * @file     example_advanced_saml.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(SAML_VERSION_1_1, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+// phpCAS::setNoCasServerValidation();
+
+// Handle SAML logout requests that emanate from the CAS host exclusively.
+// Failure to restrict SAML logout requests to authorized hosts could
+// allow denial of service attacks where at the least the server is
+// tied up parsing bogus XML messages.
+phpCAS::handleLogoutRequests(true, $cas_real_hosts);
+
+// Force CAS authentication on any page that includes this file
+phpCAS::forceAuthentication();
+
+// Some small code triggered by the logout button\r
+if (isset($_REQUEST['logout'])) {\r
+    phpCAS::logout();\r
+}
+?>
+<html>
+  <head>
+    <title>Advanced SAML 1.1 example</title>
+  </head>
+  <body>
+<h2>Advanced SAML 1.1 example</h2>
+<?php require 'script_info.php' ?>
+
+Authentication succeeded for user
+<strong><?php echo phpCAS::getUser(); ?></strong>.
+
+<h3>User Attributes</h3>
+<ul>
+<?php
+foreach (phpCAS::getAttributes() as $key => $value) {
+    if (is_array($value)) {
+        echo '<li>', $key, ':<ol>';
+        foreach ($value as $item) {
+            echo '<li><strong>', $item, '</strong></li>';
+        }
+        echo '</ol></li>';
+    } else {
+        echo '<li>', $key, ': <strong>', $value, '</strong></li>' . PHP_EOL;
+    }
+}
+    ?>
+</ul>
+<p><a href="?logout=">Logout</a></p>
+</body>
+</html>
\ No newline at end of file
diff --git a/CAS/docs/examples/example_custom_urls.php b/CAS/docs/examples/example_custom_urls.php
new file mode 100644 (file)
index 0000000..0180973
--- /dev/null
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * Example for overriding validation urls
+ *
+ * PHP Version 5
+ *
+ * @file     example_custom_urls.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// Override the validation url for any (ST and PT) CAS 2.0 validation
+phpCAS::setServerProxyValidateURL('https://cas.example.org:1443/proxyValidate');
+// Override the validation url for any CAS 1.0 validation
+//phpCAS::setServerServiceValidateURL('https://cas.example.org:1443/serviceValidate');
+//Override the validation url for any SAML11 validation
+//phpCAS::setServerSamlValidateURL('https://cas.example.org:1443/samlValidate');
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// logout if desired
+if (isset($_REQUEST['logout'])) {
+    phpCAS::logout();
+}
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>phpCAS simple client</title>
+  </head>
+  <body>
+    <h1>Successfull Authentication!</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+    <p><a href="?logout=">Logout</a></p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_gateway.php b/CAS/docs/examples/example_gateway.php
new file mode 100644 (file)
index 0000000..25be1a2
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Example that uses the CAS gateway feature
+ *
+ * PHP Version 5
+ *
+ * @file     example_gateway.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+if (isset($_REQUEST['logout'])) {
+    phpCAS::logout();
+}
+if (isset($_REQUEST['login'])) {
+    phpCAS::forceAuthentication();
+}
+
+// check CAS authentication
+$auth = phpCAS::checkAuthentication();
+
+?>
+<html>
+  <head>
+    <title>phpCAS simple client</title>
+  </head>
+  <body>
+<?php
+if ($auth) {
+    // for this test, simply print that the authentication was successfull
+        ?>
+    <h1>Successfull Authentication!</h1>
+    <?php include 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p><a href="?logout=">Logout</a></p><?php
+} else {
+                                        ?>
+    <h1>Guest mode</h1>
+    <p><a href="?login=">Login</a></p><?php
+}
+                                      ?>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_html.php b/CAS/docs/examples/example_html.php
new file mode 100644 (file)
index 0000000..204a83f
--- /dev/null
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * Example that changes html of phpcas messages
+ *
+ * PHP Version 5
+ *
+ * @file     example_html.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// customize HTML output
+phpCAS::setHTMLHeader(
+    '<html>
+  <head>
+    <title>__TITLE__</title>
+  </head>
+  <body>
+  <h1>__TITLE__</h1>'
+);
+phpCAS::setHTMLFooter(
+    '<hr>
+    <address>
+      phpCAS __PHPCAS_VERSION__,
+      CAS __CAS_VERSION__ (__SERVER_BASE_URL__)
+    </address>
+  </body>
+</html>'
+);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>phpCAS simple client with HTML output customization</title>
+  </head>
+  <body>
+    <h1>Successfull Authentication!</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_lang.php b/CAS/docs/examples/example_lang.php
new file mode 100644 (file)
index 0000000..1e12257
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ *  Example that changes language of phpcas pages
+ *
+ * PHP Version 5
+ *
+ * @file     example_lang.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// set the language to french
+phpCAS::setLang(PHPCAS_LANG_FRENCH);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>Exemple d'internationalisation de phpCAS</title>
+  </head>
+  <body>
+    <h1>Authentification r&eacute;ussie&nbsp;!</h1>
+    <?php require 'script_info.php' ?>
+    <p>L'utilisateur connect&eacute; est <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>La version de phpCAS est <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_logout.php b/CAS/docs/examples/example_logout.php
new file mode 100644 (file)
index 0000000..4eb1562
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ *  Example for handling logout requests
+ *
+ * PHP Version 5
+ *
+ * @file     example_logout.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// handle incoming logout requests
+phpCAS::handleLogoutRequests();
+
+// Or as an advanced featue handle SAML logout requests that emanate from the
+// CAS host exclusively.
+// Failure to restrict SAML logout requests to authorized hosts could
+// allow denial of service attacks where at the least the server is
+// tied up parsing bogus XML messages.
+// phpCAS::handleLogoutRequests(true, $cas_real_hosts);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>phpCAS simple client</title>
+  </head>
+  <body>
+    <h1>Successfull Authentication!</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_no_ssl_cn_validation.php b/CAS/docs/examples/example_no_ssl_cn_validation.php
new file mode 100644 (file)
index 0000000..b16e1e4
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ *   Example for diabling SSL CN valdiation
+ *
+ * PHP Version 5
+ *
+ * @file     example_simple.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+// phpCAS::setNoCasServerValidation();
+// You can also disable the validation of the certficate CN. This means the
+// certificate must be valid but the CN of the certificate must not match the
+// IP or hostname you are using to access the server
+phpCAS::setCasServerCACert($cas_server_ca_cert_path, false);
+
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// logout if desired
+if (isset($_REQUEST['logout'])) {
+       phpCAS::logout();
+}
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>phpCAS simple client</title>
+  </head>
+  <body>
+    <h1>Successfull Authentication!</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+    <p><a href="?logout=">Logout</a></p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_pgt_storage_db.php b/CAS/docs/examples/example_pgt_storage_db.php
new file mode 100644 (file)
index 0000000..f759a0e
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+
+/**
+ *  Example that changes the storage of the pgt tickets
+ *
+ * PHP Version 5
+ *
+ * @file     example_pgt_storage_db.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// set PGT storage to file in plain format in the same directory as session files
+phpCAS::setPGTStorageDB($db, $db_user, $db_password, $db_table);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy example with PGT storage to a database</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxy example with PGT storage to file</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+flush();
+// call a service and change the color depending on the result
+if (phpCAS::serviceWeb($serviceUrl, $err_code, $output)) {
+    echo '<div class="success">';
+} else {
+    echo '<div class="error">';
+}
+echo $output;
+echo '</div>';
+                                                             ?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_pgt_storage_file.php b/CAS/docs/examples/example_pgt_storage_file.php
new file mode 100644 (file)
index 0000000..908892e
--- /dev/null
@@ -0,0 +1,72 @@
+<?php
+
+/**
+*  Example that changes the storage of the pgt tickets to file
+*
+* PHP Version 5
+*
+* @file     example_pgt_storage_db.php
+* @category Authentication
+* @package  PhpCAS
+* @author   Joachim Fritschi <jfritschi@freenet.de>
+* @author   Adam Franco <afranco@middlebury.edu>
+* @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+* @link     https://wiki.jasig.org/display/CASC/phpCAS
+*/
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// set PGT storage to file in plain format in the same directory as session files
+phpCAS::setPGTStorageFile(session_save_path());
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy example with PGT storage to file</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxy example with PGT storage to file</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+  flush();
+  // call a service and change the color depending on the result
+if ( phpCAS::serviceWeb($serviceUrl, $err_code, $output) ) {
+    echo '<div class="success">';
+} else {
+    echo '<div class="error">';
+}
+  echo $output;
+  echo '</div>';
+?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_proxy_GET.php b/CAS/docs/examples/example_proxy_GET.php
new file mode 100644 (file)
index 0000000..ba46e34
--- /dev/null
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ *  Example for a proxy that makes a GET request.
+ *
+ * PHP Version 5
+ *
+ * @file     example_proxy_GET.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy example #2</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxied proxy example</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+flush();
+
+// call a service and change the color depending on the result
+try {
+    $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
+    $service->setUrl($serviceUrl);
+    $service->send();
+    if ($service->getResponseStatusCode() == 200) {
+        echo '<div class="success">';
+        echo $service->getResponseBody();
+        echo '</div>';
+    } else {
+        // The service responded with an error code 404, 500, etc.
+        echo '<div class="error">';
+        echo 'The service responded with a '
+        . $service->getResponseStatusCode() . ' error.';
+        echo '</div>';
+    }
+} catch (CAS_ProxyTicketException $e) {
+    if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) {
+        echo '<div class="error">';
+        echo "Your login has timed out. You need to log in again.";
+        echo '</div>';
+    } else {
+        // Other proxy ticket errors are from bad request format (shouldn't happen)
+        // or CAS server failure (unlikely) so lets just stop if we hit those.
+        throw $e;
+    }
+} catch (CAS_ProxiedService_Exception $e) {
+    // Something prevented the service request from being sent or received.
+    // We didn't even get a valid error response (404, 500, etc), so this
+    // might be caused by a network error or a DNS resolution failure.
+    // We could handle it in some way, but for now we will just stop.
+    throw $e;
+}
+
+                                                             ?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_proxy_POST.php b/CAS/docs/examples/example_proxy_POST.php
new file mode 100644 (file)
index 0000000..6e03226
--- /dev/null
@@ -0,0 +1,101 @@
+<?php
+
+/**
+ *  Example for a proxy that makes a POST request.
+ *
+ * PHP Version 5
+ *
+ * @file     example_proxy_POST.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+$serviceUrl = $curbase . $curdir . 'example_service_POST.php';
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy POST example</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxy POST example</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+flush();
+
+// call a service and change the color depending on the result
+try {
+    $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
+    $service->setUrl($serviceUrl);
+    $service->setContentType('application/x-www-form-urlencoded');
+    $service->setBody('favorite_color=blue');
+    $service->send();
+    if ($service->getResponseStatusCode() == 200) {
+        echo '<div class="success">';
+        echo $service->getResponseBody();
+        echo '</div>';
+    } else {
+        // The service responded with an error code 404, 500, etc.
+        echo '<div class="error">';
+        echo 'The service responded with a '
+        . $service->getResponseStatusCode() . ' error.';
+        echo $service->getResponseBody();
+        echo '</div>';
+    }
+} catch (CAS_ProxyTicketException $e) {
+    if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) {
+        echo '<div class="error">';
+        echo "Your login has timed out. You need to log in again.";
+        echo '</div>';
+    } else {
+        // Other proxy ticket errors are from bad request format (shouldn't happen)
+        // or CAS server failure (unlikely) so lets just stop if we hit those.
+        throw $e;
+    }
+} catch (CAS_ProxiedService_Exception $e) {
+    // Something prevented the service request from being sent or received.
+    // We didn't even get a valid error response (404, 500, etc), so this
+    // might be caused by a network error or a DNS resolution failure.
+    // We could handle it in some way, but for now we will just stop.
+    throw $e;
+}
+
+                                                             ?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_proxy_rebroadcast.php b/CAS/docs/examples/example_proxy_rebroadcast.php
new file mode 100644 (file)
index 0000000..453e860
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ *  Example for a proxy that rebroadcasts all PGTs to different servers in the
+ *  cluster
+ *
+ * PHP Version 5
+ *
+ * @file     example_proxy_rebroadcast.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// Set the nodes for rebroadcasting pgtIou/pgtId and logoutRequest
+phpCAS::addRebroadcastNode($rebroadcast_node_1);
+phpCAS::addRebroadcastNode($rebroadcast_node_2);
+
+// handle incoming logout requests
+phpCAS::handleLogoutRequests();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy rebroadcast example</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxy rebroadcast example</h1>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_proxy_serviceWeb.php b/CAS/docs/examples/example_proxy_serviceWeb.php
new file mode 100644 (file)
index 0000000..69d1e7e
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ * Example for a proxy with session usage
+ *
+ * PHP Version 5
+ *
+ * @file     example_proxy_GET.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxied proxy example (with sessioning)</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxied proxy example (with sessioning)</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+flush();
+// call a service and change the color depending on the result
+if (phpCAS::serviceWeb($serviceUrl, $err_code, $output)) {
+    echo '<div class="success">';
+} else {
+    echo '<div class="error">';
+}
+echo $output;
+echo '</div>';
+                                                             ?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_proxy_serviceWeb_chaining.php b/CAS/docs/examples/example_proxy_serviceWeb_chaining.php
new file mode 100644 (file)
index 0000000..b4b8de8
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+/**
+ *  Example for a proxy with session usage
+ *
+ * PHP Version 5
+ *
+ * @file     example_proxy_serviceWeb_chaining.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxy example #2</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>phpCAS proxied proxy example</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl2; ?></h2>
+<?php
+flush();
+// call a service and change the color depending on the result
+if (phpCAS::serviceWeb($serviceUrl2, $err_code, $output)) {
+    echo '<div class="success">';
+} else {
+    echo '<div class="error">';
+}
+echo $output;
+echo '</div>';
+                                                              ?>
+  </body>
+</html>
diff --git a/CAS/docs/examples/example_service.php b/CAS/docs/examples/example_service.php
new file mode 100644 (file)
index 0000000..9af528d
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+
+/**
+ * Example for proxied service with session support
+ *
+ * PHP Version 5
+ *
+ * @file     example_service.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// If you want your service to be proxied you have to enable it (default
+// disabled) and define an accepable list of proxies that are allowed to
+// proxy your service.
+//
+// Add each allowed proxy definition object. For the normal CAS_ProxyChain
+// class, the constructor takes an array of proxies to match. The list is in
+// reverse just as seen from the service. Proxies have to be defined in reverse
+// from the service to the user. If a user hits service A and gets proxied via
+// B to service C the list of acceptable on C would be array(B,A). The definition
+// of an individual proxy can be either a string or a regexp (preg_match is used)
+// that will be matched against the proxy list supplied by the cas server
+// when validating the proxy tickets. The strings are compared starting from
+// the beginning and must fully match with the proxies in the list.
+// Example:
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             'https://app.example.com/'
+//                     )));
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             '/^https:\/\/app[0-9]\.example\.com\/rest\//',
+//                             'http://client.example.com/'
+//                     )));
+phpCAS::allowProxyChain(new CAS_ProxyChain(array($pgtUrlRegexp)));
+phpCAS::allowProxyChain(
+    new CAS_ProxyChain(
+        array('/^' . $pgtBase . 'example_service_that_proxies.php$/',
+            '/^' . $pgtBase . 'example_proxy_serviceWeb_chaining.php$/'
+        )
+    )
+);
+
+// For quick testing or in certain production screnarios you might want to
+// allow allow any other valid service to proxy your service. To do so, add
+// the "Any" chain:
+//             phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+// THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+// IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+// ON THIS SERVICE.
+//phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+print '<h1>I am a service that can be proxied.</h1>';
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+require 'script_info.php';
+
+// for this test, simply print that the authentication was successfull
+echo '<p>The user\'s login is <b>' . phpCAS::getUser() . '</b>.</p>';
+
+// increment the number of requests of the session and print it
+if (!isset($_SESSION['n'])) {
+    $_SESSION['n'] = 0;
+}
+echo '<p>request #' . (++$_SESSION['n']) . '</p>';
+
+?>
diff --git a/CAS/docs/examples/example_service_POST.php b/CAS/docs/examples/example_service_POST.php
new file mode 100644 (file)
index 0000000..31f3d5f
--- /dev/null
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ *   Example for proxied service with session support and POST support
+ *
+ * PHP Version 5
+ *
+ * @file     example_service_POST.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// If you want your service to be proxied you have to enable it (default
+// disabled) and define an accepable list of proxies that are allowed to
+// proxy your service.
+//
+// Add each allowed proxy definition object. For the normal CAS_ProxyChain
+// class, the constructor takes an array of proxies to match. The list is in
+// reverse just as seen from the service. Proxies have to be defined in reverse
+// from the service to the user. If a user hits service A and gets proxied via
+// B to service C the list of acceptable on C would be array(B,A). The definition
+// of an individual proxy can be either a string or a regexp (preg_match is used)
+// that will be matched against the proxy list supplied by the cas server
+// when validating the proxy tickets. The strings are compared starting from
+// the beginning and must fully match with the proxies in the list.
+// Example:
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             'https://app.example.com/'
+//                     )));
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             '/^https:\/\/app[0-9]\.example\.com\/rest\//',
+//                             'http://client.example.com/'
+//                     )));
+phpCAS::allowProxyChain(new CAS_ProxyChain(array($pgtUrlRegexp)));
+
+// For quick testing or in certain production screnarios you might want to
+// allow allow any other valid service to proxy your service. To do so, add
+// the "Any" chain:
+//             phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+// THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+// IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+// ON THIS SERVICE.
+//phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+if ($_SERVER['REQUEST_METHOD'] != 'POST') {
+    header('HTTP/1.1 400 Bad Request');
+    print
+        "<h1>I only respond to POST requests. This is a "
+        . $_SERVER['REQUEST_METHOD'] . " request.</h1>";
+    exit;
+}
+if (empty($_POST['favorite_color'])) {
+    header('HTTP/1.1 400 Bad Request');
+    print '<h1>You must post a <strong>favorite_color</strong>.</h1>';
+    exit;
+}
+
+print '<h1>I am a service that responds to POST requests.</h1>';
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+require 'script_info.php';
+
+// for this test, simply print that the authentication was successfull
+echo '<p>The user\'s login is <b>' . phpCAS::getUser() . '</b>.</p>';
+
+print
+    '<h1>Your favorite color is ' . htmlentities($_POST['favorite_color'])
+    . '</h1>';
+
+// increment the number of requests of the session and print it
+if (!isset($_SESSION['n'])) {
+    $_SESSION['n'] = 0;
+}
+echo '<p>request #' . (++$_SESSION['n']) . '</p>';
+
diff --git a/CAS/docs/examples/example_service_that_proxies.php b/CAS/docs/examples/example_service_that_proxies.php
new file mode 100644 (file)
index 0000000..dc83b7b
--- /dev/null
@@ -0,0 +1,104 @@
+<?php
+
+/**
+ *  Example for a proxied proxy
+ *
+ * PHP Version 5
+ *
+ * @file     example_service_that_proxies.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::proxy(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// If you want your service to be proxied you have to enable it (default
+// disabled) and define an accepable list of proxies that are allowed to
+// proxy your service.
+//
+// Add each allowed proxy definition object. For the normal CAS_ProxyChain
+// class, the constructor takes an array of proxies to match. The list is in
+// reverse just as seen from the service. Proxies have to be defined in reverse
+// from the service to the user. If a user hits service A and gets proxied via
+// B to service C the list of acceptable on C would be array(B,A). The definition
+// of an individual proxy can be either a string or a regexp (preg_match is used)
+// that will be matched against the proxy list supplied by the cas server
+// when validating the proxy tickets. The strings are compared starting from
+// the beginning and must fully match with the proxies in the list.
+// Example:
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             'https://app.example.com/'
+//                     )));
+//             phpCAS::allowProxyChain(new CAS_ProxyChain(array(
+//                             '/^https:\/\/app[0-9]\.example\.com\/rest\//',
+//                             'http://client.example.com/'
+//                     )));
+phpCAS::allowProxyChain(new CAS_ProxyChain(array($pgtUrlRegexp)));
+
+// For quick testing or in certain production screnarios you might want to
+// allow allow any other valid service to proxy your service. To do so, add
+// the "Any" chain:
+//             phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+// THIS SETTING IS HOWEVER NOT RECOMMENDED FOR PRODUCTION AND HAS SECURITY
+// IMPLICATIONS: YOU ARE ALLOWING ANY SERVICE TO ACT ON BEHALF OF A USER
+// ON THIS SERVICE.
+//phpcas::allowProxyChain(new CAS_ProxyChain_Any);
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// moreover, a PGT was retrieved from the CAS server that will
+// permit to gain accesses to new services.
+
+
+
+?>
+<html>
+  <head>
+    <title>phpCAS proxied proxy service example</title>
+    <link rel="stylesheet" type='text/css' href='example.css'/>
+  </head>
+  <body>
+    <h1>I am a service that can be proxied. In turn, I proxy another service.</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <h2>Response from service <?php echo $serviceUrl; ?></h2>
+<?php
+  flush();
+  // call a service and change the color depending on the result
+if ( phpCAS::serviceWeb($serviceUrl, $err_code, $output) ) {
+    echo '<div class="success">';
+} else {
+    echo '<div class="error">';
+}
+  echo $output;
+  echo '</div>';
+?>
+  </body>
+</html>
+
diff --git a/CAS/docs/examples/example_simple.php b/CAS/docs/examples/example_simple.php
new file mode 100644 (file)
index 0000000..c0a11c5
--- /dev/null
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ *   Example for a simple cas 2.0 client
+ *
+ * PHP Version 5
+ *
+ * @file     example_simple.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */
+
+// Load the settings from the central config file
+require_once 'config.php';
+// Load the CAS lib
+require_once $phpcas_path . '/CAS.php';
+
+// Uncomment to enable debugging
+phpCAS::setDebug();
+
+// Initialize phpCAS
+phpCAS::client(CAS_VERSION_2_0, $cas_host, $cas_port, $cas_context);
+
+// For production use set the CA certificate that is the issuer of the cert
+// on the CAS server and uncomment the line below
+// phpCAS::setCasServerCACert($cas_server_ca_cert_path);
+
+// For quick testing you can disable SSL validation of the CAS server.
+// THIS SETTING IS NOT RECOMMENDED FOR PRODUCTION.
+// VALIDATING THE CAS SERVER IS CRUCIAL TO THE SECURITY OF THE CAS PROTOCOL!
+phpCAS::setNoCasServerValidation();
+
+// force CAS authentication
+phpCAS::forceAuthentication();
+
+// at this step, the user has been authenticated by the CAS server
+// and the user's login name can be read with phpCAS::getUser().
+
+// logout if desired
+if (isset($_REQUEST['logout'])) {
+       phpCAS::logout();
+}
+
+// for this test, simply print that the authentication was successfull
+?>
+<html>
+  <head>
+    <title>phpCAS simple client</title>
+  </head>
+  <body>
+    <h1>Successfull Authentication!</h1>
+    <?php require 'script_info.php' ?>
+    <p>the user's login is <b><?php echo phpCAS::getUser(); ?></b>.</p>
+    <p>phpCAS version is <b><?php echo phpCAS::getVersion(); ?></b>.</p>
+    <p><a href="?logout=">Logout</a></p>
+  </body>
+</html>
diff --git a/CAS/docs/examples/script_info.php b/CAS/docs/examples/script_info.php
new file mode 100644 (file)
index 0000000..0a6c954
--- /dev/null
@@ -0,0 +1,20 @@
+<?php
+/**
+ *  Small script to add some info about the example script that is running.
+ *  Adds some info that makes it easier to distinguish different proxy sessions
+ *
+ * PHP Version 5
+ *
+ * @file     script_info.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Joachim Fritschi <jfritschi@freenet.de>
+ * @author   Adam Franco <afranco@middlebury.edu>
+ * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
+ * @link     https://wiki.jasig.org/display/CASC/phpCAS
+ */ ?>
+    <dl style='border: 1px dotted; padding: 5px;'>
+      <dt>Current script</dt><dd><?php print basename($_SERVER['SCRIPT_NAME']); ?></dd>
+      <dt>session_name():</dt><dd> <?php print session_name(); ?></dd>
+      <dt>session_id():</dt><dd> <?php print session_id(); ?></dd>
+    </dl>
\ No newline at end of file
diff --git a/CAS/docs/images/esup-portail.png b/CAS/docs/images/esup-portail.png
new file mode 100644 (file)
index 0000000..ed6e666
Binary files /dev/null and b/CAS/docs/images/esup-portail.png differ
diff --git a/CAS/docs/images/jasig.png b/CAS/docs/images/jasig.png
new file mode 100644 (file)
index 0000000..38952bd
Binary files /dev/null and b/CAS/docs/images/jasig.png differ
diff --git a/CAS/docs/images/phpcas.png b/CAS/docs/images/phpcas.png
new file mode 100644 (file)
index 0000000..0fed45d
Binary files /dev/null and b/CAS/docs/images/phpcas.png differ
diff --git a/CAS/docs/index.html b/CAS/docs/index.html
new file mode 100644 (file)
index 0000000..f478f52
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\r
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\r
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\r
+  <head>\r
+    <title>phpCAS</title>\r
+  </head>\r
+  <body>\r
+       <p><img src="images/phpcas.png" width="191" height="68"/></p>\r
+       <p>phpCAS documentation is hosted at <a href="https://wiki.jasig.org/display/CASC/phpCAS">https://wiki.jasig.org/display/CASC/phpCAS</a>.</p>\r
+       <ul>\r
+         <li><a href="examples">examples</a></li>\r
+         <li><a href="http://downloads.jasig.org/cas-clients/php/1.3.2/docs/api/">source documentation</a></li>\r
+  </ul>\r
+       <p><img src="images/esup-portail.png" width="182" height="68"/> <img src="images/jasig.png" width="169" height="87"/></p>\r
+       <p>&nbsp;</p>\r
+  </body>\r
+</html>\r
+  \r
index a01801d..582c147 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -3,6 +3,7 @@
  * Compatible with Piwik 2.1
  * Removed the "additional root logins" option (Piwik handles multiple superusers natively now)
  * Added custom CAS login image
  * Compatible with Piwik 2.1
  * Removed the "additional root logins" option (Piwik handles multiple superusers natively now)
  * Added custom CAS login image
+ * Upgrade to phpCAS-1.3.2
 
 0.6.3
  * Bugfix: Added $this->setBasicVariablesView($view) to Controller.php to fix missing variables issue 
 
 0.6.3
  * Bugfix: Added $this->setBasicVariablesView($view) to Controller.php to fix missing variables issue