From bb61a1e3b6b54cff49083348870106e4ac303dfd Mon Sep 17 00:00:00 2001 From: Adam Zammit Date: Fri, 18 Dec 2015 09:24:51 +1100 Subject: [PATCH 1/4] Fixed bug: When self completing group by group or all-in-one, numeric key presses may change previous answers --- include/limesurvey/replacements.php | 1 + include/limesurvey/scripts/survey_runtime.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/limesurvey/replacements.php b/include/limesurvey/replacements.php index 27be5b0d..aecd4ca8 100644 --- a/include/limesurvey/replacements.php +++ b/include/limesurvey/replacements.php @@ -74,6 +74,7 @@ function templatereplace($line, $replacements=array(), $anonymized=false, $quest { $(".text").focus(); $(".textarea").focus(); + document[\'onkeypress\'] = checkEnter; }); '; } diff --git a/include/limesurvey/scripts/survey_runtime.js b/include/limesurvey/scripts/survey_runtime.js index a5ce8aa7..e67aaeb1 100644 --- a/include/limesurvey/scripts/survey_runtime.js +++ b/include/limesurvey/scripts/survey_runtime.js @@ -6,7 +6,7 @@ $(document).ready(function() if (typeof checkconditions!='undefined') checkconditions(); if (typeof template_onload!='undefined') template_onload(); prepareCellAdapters(); - document['onkeypress'] = checkEnter; +// document['onkeypress'] = checkEnter; if (typeof(focus_element) != 'undefined') { $(focus_element).focus(); From 97b636a3ffa88b7eb805866bc82459df8d1cbf93 Mon Sep 17 00:00:00 2001 From: Adam Zammit Date: Fri, 18 Dec 2015 12:42:07 +1100 Subject: [PATCH 2/4] Added note about file permissions to README --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 7fc4c2c9..02a13bea 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ If you have a previous version of queXS installed, please check the CHANGELOG fi ``` #Download and extract queXS to your webroot unzip quexs-1.14.0.zip -d /var/www/html +cd /var/www/html/quexs #Create a MySQL/mariadb database mysqladmin create quexs #Import the database structure from the database/quexs.sql file @@ -29,6 +30,9 @@ mysql -uroot quexs < database/quexs.sql mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql #Create the default config file cp config.inc.local.php.example config.inc.local.php +#Update file permissions +chown www-data:www-data -R include/limesurvey/tmp/ +chown www-data:www-data -R include/limesurvey/upload/ ``` Then browse to the queXS URL and login using the default credentials (admin/password) From 700a74bad82b5624d5c3d5dfca4f1c004b7cee5d Mon Sep 17 00:00:00 2001 From: Adam Zammit Date: Fri, 18 Dec 2015 12:58:14 +1100 Subject: [PATCH 3/4] Updated phpCAS to 1.3.4 --- .../limesurvey/admin/classes/phpCAS/CAS.php | 2135 +++++---- .../phpCAS/CAS/AuthenticationException.php | 108 + .../admin/classes/phpCAS/CAS/Autoload.php | 105 + .../admin/classes/phpCAS/CAS/Client.php | 3867 +++++++++++++++++ .../admin/classes/phpCAS/CAS/CookieJar.php | 385 ++ .../admin/classes/phpCAS/CAS/Exception.php | 59 + .../CAS/GracefullTerminationException.php | 86 + .../phpCAS/CAS/InvalidArgumentException.php | 46 + .../classes/phpCAS/CAS/Languages/Catalan.php | 114 + .../classes/phpCAS/CAS/Languages/English.php | 114 + .../classes/phpCAS/CAS/Languages/French.php | 116 + .../classes/phpCAS/CAS/Languages/German.php | 116 + .../classes/phpCAS/CAS/Languages/Greek.php | 115 + .../classes/phpCAS/CAS/Languages/Japanese.php | 113 + .../CAS/Languages/LanguageInterface.php | 96 + .../classes/phpCAS/CAS/Languages/Spanish.php | 117 + ...uenceBeforeAuthenticationCallException.php | 56 + .../OutOfSequenceBeforeClientException.php | 58 + .../CAS/OutOfSequenceBeforeProxyException.php | 59 + .../phpCAS/CAS/OutOfSequenceException.php | 49 + .../{pgt-main.php => AbstractStorage.php} | 102 +- .../classes/phpCAS/CAS/PGTStorage/Db.php | 440 ++ .../CAS/PGTStorage/{pgt-file.php => File.php} | 165 +- .../classes/phpCAS/CAS/PGTStorage/pgt-db.php | 191 - .../classes/phpCAS/CAS/ProxiedService.php | 72 + .../phpCAS/CAS/ProxiedService/Abstract.php | 149 + .../phpCAS/CAS/ProxiedService/Exception.php | 46 + .../phpCAS/CAS/ProxiedService/Http.php | 91 + .../CAS/ProxiedService/Http/Abstract.php | 360 ++ .../phpCAS/CAS/ProxiedService/Http/Get.php | 85 + .../phpCAS/CAS/ProxiedService/Http/Post.php | 152 + .../phpCAS/CAS/ProxiedService/Imap.php | 280 ++ .../phpCAS/CAS/ProxiedService/Testable.php | 75 + .../admin/classes/phpCAS/CAS/ProxyChain.php | 127 + .../phpCAS/CAS/ProxyChain/AllowedList.php | 119 + .../classes/phpCAS/CAS/ProxyChain/Any.php | 64 + .../phpCAS/CAS/ProxyChain/Interface.php | 53 + .../classes/phpCAS/CAS/ProxyChain/Trusted.php | 59 + .../phpCAS/CAS/ProxyTicketException.php | 71 + .../phpCAS/CAS/Request/AbstractRequest.php | 379 ++ .../phpCAS/CAS/Request/CurlMultiRequest.php | 146 + .../phpCAS/CAS/Request/CurlRequest.php | 200 + .../classes/phpCAS/CAS/Request/Exception.php | 45 + .../CAS/Request/MultiRequestInterface.php | 83 + .../phpCAS/CAS/Request/RequestInterface.php | 179 + .../phpCAS/CAS/TypeMismatchException.php | 70 + .../admin/classes/phpCAS/CAS/client.php | 2297 ---------- .../classes/phpCAS/CAS/domxml-php4-php5.php | 277 -- .../classes/phpCAS/CAS/languages/catalan.php | 28 - .../classes/phpCAS/CAS/languages/english.php | 28 - .../classes/phpCAS/CAS/languages/french.php | 29 - .../classes/phpCAS/CAS/languages/german.php | 28 - .../classes/phpCAS/CAS/languages/greek.php | 28 - .../classes/phpCAS/CAS/languages/japanese.php | 28 - .../phpCAS/CAS/languages/languages.php | 24 - .../classes/phpCAS/CAS/languages/spanish.php | 28 - .../limesurvey/admin/classes/phpCAS/LICENSE | 201 + .../limesurvey/admin/classes/phpCAS/NOTICE | 81 + .../limesurvey/admin/classes/phpCAS/README | 36 - .../limesurvey/admin/classes/phpCAS/README.md | 31 + .../admin/classes/phpCAS/docs/Building | 34 + .../admin/classes/phpCAS/docs/ChangeLog | 565 +++ .../admin/classes/phpCAS/docs/Upgrading | 100 + .../phpCAS/docs/examples/config.example.php | 104 + .../examples/create_pgt_storage_db_table.php | 53 + .../classes/phpCAS/docs/examples/example.css | 10 + .../docs/examples/example_advanced_saml11.php | 82 + .../docs/examples/example_custom_urls.php | 70 + .../phpCAS/docs/examples/example_gateway.php | 71 + .../docs/examples/example_hardening.php | 85 + .../phpCAS/docs/examples/example_html.php | 76 + .../phpCAS/docs/examples/example_lang.php | 63 + .../phpCAS/docs/examples/example_logout.php | 64 + .../examples/example_no_ssl_cn_validation.php | 68 + .../docs/examples/example_pgt_storage_db.php | 74 + .../examples/example_pgt_storage_file.php | 74 + .../docs/examples/example_proxy_GET.php | 98 + .../docs/examples/example_proxy_POST.php | 103 + .../examples/example_proxy_rebroadcast.php | 63 + .../examples/example_proxy_serviceWeb.php | 71 + .../example_proxy_serviceWeb_chaining.php | 71 + .../phpCAS/docs/examples/example_renew.php | 72 + .../phpCAS/docs/examples/example_service.php | 96 + .../docs/examples/example_service_POST.php | 105 + .../examples/example_service_that_proxies.php | 106 + .../phpCAS/docs/examples/example_simple.php | 63 + .../phpCAS/docs/examples/script_info.php | 20 + .../phpCAS/docs/images/esup-portail.png | Bin 0 -> 2621 bytes .../classes/phpCAS/docs/images/jasig.png | Bin 0 -> 2384 bytes .../classes/phpCAS/docs/images/phpcas.png | Bin 0 -> 6771 bytes .../admin/classes/phpCAS/docs/index.html | 19 + 91 files changed, 13381 insertions(+), 3960 deletions(-) create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/AuthenticationException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Autoload.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Client.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/CookieJar.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Exception.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/GracefullTerminationException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/InvalidArgumentException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/Catalan.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/English.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/French.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/German.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/Greek.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/Japanese.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/LanguageInterface.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Languages/Spanish.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeAuthenticationCallException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeClientException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeProxyException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceException.php rename include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/{pgt-main.php => AbstractStorage.php} (60%) create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/Db.php rename include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/{pgt-file.php => File.php} (52%) delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-db.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Abstract.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Exception.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Abstract.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Get.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Post.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Imap.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Testable.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/AllowedList.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Any.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Interface.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Trusted.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/ProxyTicketException.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/AbstractRequest.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlMultiRequest.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlRequest.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/Exception.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/MultiRequestInterface.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/Request/RequestInterface.php create mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/TypeMismatchException.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/client.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/domxml-php4-php5.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/catalan.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/english.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/french.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/german.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/greek.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/japanese.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/languages.php delete mode 100644 include/limesurvey/admin/classes/phpCAS/CAS/languages/spanish.php create mode 100644 include/limesurvey/admin/classes/phpCAS/LICENSE create mode 100644 include/limesurvey/admin/classes/phpCAS/NOTICE delete mode 100644 include/limesurvey/admin/classes/phpCAS/README create mode 100644 include/limesurvey/admin/classes/phpCAS/README.md create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/Building create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/ChangeLog create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/Upgrading create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/config.example.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/create_pgt_storage_db_table.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example.css create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_advanced_saml11.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_custom_urls.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_gateway.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_hardening.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_html.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_lang.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_logout.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_no_ssl_cn_validation.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_db.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_file.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_GET.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_POST.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_rebroadcast.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb_chaining.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_renew.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_service.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_POST.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_that_proxies.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/example_simple.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/examples/script_info.php create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/images/esup-portail.png create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/images/jasig.png create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/images/phpcas.png create mode 100644 include/limesurvey/admin/classes/phpCAS/docs/index.html diff --git a/include/limesurvey/admin/classes/phpCAS/CAS.php b/include/limesurvey/admin/classes/phpCAS/CAS.php index 7b994919..3d84809c 100644 --- a/include/limesurvey/admin/classes/phpCAS/CAS.php +++ b/include/limesurvey/admin/classes/phpCAS/CAS.php @@ -1,33 +1,57 @@ =')) { -// require_once(dirname(__FILE__).'/CAS/domxml-php4-php5.php'); -//} - -/** - * @file CAS/CAS.php - * Interface class of the phpCAS library + * 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 + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @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 // ######################################################################## @@ -39,11 +63,8 @@ if (!$_SERVER['REQUEST_URI']) { /** * phpCAS version. accessible for the user by phpCAS::getVersion(). */ -define('PHPCAS_VERSION','1.0.1'); +define('PHPCAS_VERSION', '1.3.4'); -// ------------------------------------------------------------------------ -// CAS VERSIONS -// ------------------------------------------------------------------------ /** * @addtogroup public * @{ @@ -52,11 +73,75 @@ define('PHPCAS_VERSION','1.0.1'); /** * CAS version 1.0 */ -define("CAS_VERSION_1_0",'1.0'); +define("CAS_VERSION_1_0", '1.0'); /*! * CAS version 2.0 +*/ +define("CAS_VERSION_2_0", '2.0'); +/** + * CAS version 3.0 */ -define("CAS_VERSION_2_0",'2.0'); +define("CAS_VERSION_3_0", '3.0'); + +// ------------------------------------------------------------------------ +// SAML defines +// ------------------------------------------------------------------------ + +/** + * SAML protocol + */ +define("SAML_VERSION_1_1", 'S1'); + +/** + * XML header for SAML POST + */ +define("SAML_XML_HEADER", ''); + +/** + * SOAP envelope for SAML POST + */ +define("SAML_SOAP_ENV", ''); + +/** + * SOAP body for SAML POST + */ +define("SAML_SOAP_BODY", ''); + +/** + * SAMLP request + */ +define("SAMLP_REQUEST", ''); +define("SAMLP_REQUEST_CLOSE", ''); + +/** + * SAMLP artifact tag (for the ticket) + */ +define("SAML_ASSERTION_ARTIFACT", ''); + +/** + * SAMLP close + */ +define("SAML_ASSERTION_ARTIFACT_CLOSE", ''); + +/** + * SOAP body close + */ +define("SAML_SOAP_BODY_CLOSE", ''); + +/** + * SOAP envelope close + */ +define("SAML_SOAP_ENV_CLOSE", ''); + +/** + * SAML Attributes + */ +define("SAML_ATTRIBUTES", 'SAMLATTRIBS'); + +/** + * SAML Attributes + */ +define("DEFAULT_ERROR", 'Internal script failure'); /** @} */ /** @@ -69,43 +154,7 @@ define("CAS_VERSION_2_0",'2.0'); /** * Default path used when storing PGT's to file */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH",'/tmp'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write plain text files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_PLAIN",'plain'); -/** - * phpCAS::setPGTStorageFile()'s 2nd parameter to write xml files - */ -define("CAS_PGT_STORAGE_FILE_FORMAT_XML",'xml'); -/** - * Default format used when storing PGT's to file - */ -define("CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT",CAS_PGT_STORAGE_FILE_FORMAT_PLAIN); -// ------------------------------------------------------------------------ -// DATABASE PGT STORAGE -// ------------------------------------------------------------------------ -/** - * default database type when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE",'mysql'); -/** - * default host when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME",'localhost'); -/** - * default port when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_PORT",''); -/** - * default database when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_DATABASE",'phpCAS'); -/** - * default table when storing PGT's to database - */ -define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE",'pgt'); - +define("CAS_PGT_STORAGE_FILE_DEFAULT_PATH", session_save_path()); /** @} */ // ------------------------------------------------------------------------ // SERVICE ACCESS ERRORS @@ -118,26 +167,43 @@ define("CAS_PGT_STORAGE_DB_DEFAULT_TABLE",'pgt'); /** * phpCAS::service() error code on success */ -define("PHPCAS_SERVICE_OK",0); +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); +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); +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); +define("PHPCAS_SERVICE_PT_FAILURE", 3); /** * phpCAS::service() error code when the service was not available. */ -define("PHPCAS_SERVICE_NOT AVAILABLE",4); +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'); + /** @} */ // ------------------------------------------------------------------------ @@ -148,13 +214,13 @@ define("PHPCAS_SERVICE_NOT AVAILABLE",4); * @{ */ -define("PHPCAS_LANG_ENGLISH", 'english'); -define("PHPCAS_LANG_FRENCH", 'french'); -define("PHPCAS_LANG_GREEK", 'greek'); -define("PHPCAS_LANG_GERMAN", 'german'); -define("PHPCAS_LANG_JAPANESE", 'japanese'); -define("PHPCAS_LANG_SPANISH", 'spanish'); -define("PHPCAS_LANG_CATALAN", 'catalan'); +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'); /** @} */ @@ -180,86 +246,72 @@ define("PHPCAS_LANG_DEFAULT", PHPCAS_LANG_ENGLISH); /** * The default directory for the debug file under Unix. */ -define('DEFAULT_DEBUG_DIR','/tmp/'); - -/** @} */ -// ------------------------------------------------------------------------ -// MISC -// ------------------------------------------------------------------------ -/** - * @addtogroup internalMisc - * @{ - */ - -/** - * This global variable is used by the interface class phpCAS. - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_CLIENT'] = null; - -/** - * This global variable is used to store where the initializer is called from - * (to print a comprehensive error in case of multiple calls). - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_INIT_CALL'] = array('done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?'); - -/** - * This global variable is used to store where the method checking - * the authentication is called from (to print comprehensive errors) - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_AUTH_CHECK_CALL'] = array('done' => FALSE, - 'file' => '?', - 'line' => -1, - 'method' => '?', - 'result' => FALSE); - -/** - * This global variable is used to store phpCAS debug mode. - * - * @hideinitializer - */ -$GLOBALS['PHPCAS_DEBUG'] = array('filename' => FALSE, - 'indent' => 0, - 'unique_id' => ''); +function gettmpdir() { +if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); } +if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); } +if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); } +return "/tmp"; +} +define('DEFAULT_DEBUG_DIR', gettmpdir()."/"); /** @} */ -// ######################################################################## -// CLIENT CLASS -// ######################################################################## - -// include client class -include_once(dirname(__FILE__).'/CAS/client.php'); - -// ######################################################################## -// INTERFACE CLASS -// ######################################################################## +// include the class autoloader +require_once dirname(__FILE__) . '/CAS/Autoload.php'; /** - * @class phpCAS * The phpCAS class is a simple container for the phpCAS library. It provides CAS * authentication for web applications written in PHP. * * @ingroup public - * @author Pascal Aubry - * - * \internal All its methods access the same object ($PHPCAS_CLIENT, declared - * at the end of CAS/client.php). + * @class phpCAS + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @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. + * + * @var CAS_Client + * @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; + + /** + * This variable is used to enable verbose mode + * This pevents debug info to be show to the user. Since it's a security + * feature the default is false + * + * @hideinitializer + */ + private static $_PHPCAS_VERBOSE = false; + + // ######################################################################## // INITIALIZATION // ######################################################################## @@ -271,104 +323,100 @@ class phpCAS /** * 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()). - * - * @param $server_version the version of the CAS server - * @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 */ - function client($server_version, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) - { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS::traceBegin(); - if ( is_object($PHPCAS_CLIENT) ) { - phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$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\')'); + 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'] . ')'); } - // store where the initialzer is called from - $dbg = phpCAS::backtrace(); - $PHPCAS_INIT_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__); + // 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 global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version,FALSE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); - phpCAS::traceEnd(); + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( + $server_version, false, $server_hostname, $server_port, $server_uri, + $changeSessionID + ); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + 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()). - * - * @param $server_version the version of the CAS server - * @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 */ - function proxy($server_version, - $server_hostname, - $server_port, - $server_uri, - $start_session = true) - { - global $PHPCAS_CLIENT, $PHPCAS_INIT_CALL; - - phpCAS::traceBegin(); - if ( is_object($PHPCAS_CLIENT) ) { - phpCAS::error($PHPCAS_INIT_CALL['method'].'() has already been called (at '.$PHPCAS_INIT_CALL['file'].':'.$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\')'); + 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'] . ')'); } // store where the initialzer is called from - $dbg = phpCAS::backtrace(); - $PHPCAS_INIT_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__); + $dbg = debug_backtrace(); + self::$_PHPCAS_INIT_CALL = array ( + 'done' => true, + 'file' => $dbg[0]['file'], + 'line' => $dbg[0]['line'], + 'method' => __CLASS__ . '::' . __FUNCTION__ + ); - // initialize the global object $PHPCAS_CLIENT - $PHPCAS_CLIENT = new CASClient($server_version,TRUE/*proxy*/,$server_hostname,$server_port,$server_uri,$start_session); - phpCAS::traceEnd(); + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( + $server_version, true, $server_hostname, $server_port, $server_uri, + $changeSessionID + ); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } + + /** + * Answer whether or not the client or proxy has been initialized + * + * @return bool + */ + public static function isInitialized () + { + return (is_object(self::$_PHPCAS_CLIENT)); } /** @} */ @@ -384,99 +432,126 @@ class phpCAS /** * Set/unset debug mode * - * @param $filename the name of the file used for logging, or FALSE to stop debugging. + * @param string $filename the name of the file used for logging, or false + * to stop debugging. + * + * @return void */ - function setDebug($filename='') + public static function setDebug($filename = '') { - global $PHPCAS_DEBUG; - - 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 && 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; - if ( empty($filename) ) { - if ( preg_match('/^Win.*/',getenv('OS')) ) { - if ( isset($_ENV['TMP']) ) { - $debugDir = $_ENV['TMP'].'/'; - } else if ( isset($_ENV['TEMP']) ) { - $debugDir = $_ENV['TEMP'].'/'; + } else { + if (empty ($filename)) { + if (preg_match('/^Win.*/', getenv('OS'))) { + if (isset ($_ENV['TMP'])) { + $debugDir = $_ENV['TMP'] . '/'; + } else { + $debugDir = ''; + } } else { - $debugDir = ''; + $debugDir = DEFAULT_DEBUG_DIR; } - } else { - $debugDir = DEFAULT_DEBUG_DIR; + $filename = $debugDir . 'phpCAS.log'; } - $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 ('.date("Y-m-d H:i:s").') phpCAS-' . PHPCAS_VERSION . ' ******************'); + } + } + + /** + * Enable verbose errors messages in the website output + * This is a security relevant since internal status info may leak an may + * help an attacker. Default is therefore false + * + * @param bool $verbose enable verbose output + * + * @return void + */ + public static function setVerbose($verbose) + { + if ($verbose === true) { + self::$_PHPCAS_VERBOSE = true; + } else { + self::$_PHPCAS_VERBOSE = false; } - - if ( empty($PHPCAS_DEBUG['unique_id']) ) { - $PHPCAS_DEBUG['unique_id'] = substr(strtoupper(md5(uniqid(''))),0,4); - } - - $PHPCAS_DEBUG['filename'] = $filename; - - phpCAS::trace('START ******************'); } - /** @} */ - /** - * @addtogroup internalDebug - * @{ - */ /** - * This method is a wrapper for debug_backtrace() that is not available - * in all PHP versions (>= 4.3.0 only) - */ - function backtrace() - { - if ( function_exists('debug_backtrace') ) { - return debug_backtrace(); - } else { - // poor man's hack ... but it does work ... - return array(); - } + * Show is verbose mode is on + * + * @return boot verbose + */ + public static function getVerbose() + { + return self::$_PHPCAS_VERBOSE; } /** * Logs a string in debug mode. * - * @param $str the string to write + * @param string $str the string to write * + * @return void * @private */ - function log($str) + public static function log($str) { $indent_str = "."; - global $PHPCAS_DEBUG; - if ( $PHPCAS_DEBUG['filename'] ) { - for ($i=0;$i<$PHPCAS_DEBUG['indent'];$i++) { + + 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 .= '| '; } - error_log($PHPCAS_DEBUG['unique_id'].' '.$indent_str.$str."\n",3,$PHPCAS_DEBUG['filename']); + // 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. + * This method is used by interface methods to print an error and where the + * function was originally called from. * - * @param $msg the message to print + * @param string $msg the message to print * + * @return void * @private */ - function error($msg) + public static function error($msg) { - $dbg = phpCAS::backtrace(); + phpCAS :: traceBegin(); + $dbg = debug_backtrace(); $function = '?'; $file = '?'; $line = '?'; - if ( is_array($dbg) ) { - for ( $i=1; $i\nphpCAS error: ".__CLASS__."::".$function.'(): '.htmlentities($msg)." in ".$file." on line ".$line."
\n"; - phpCAS::trace($msg); - phpCAS::traceExit(); - exit(); + if (self::$_PHPCAS_VERBOSE) { + echo "
\nphpCAS error: " . __CLASS__ . "::" . $function . '(): ' . htmlentities($msg) . " in " . $file . " on line " . $line . "
\n"; + } else { + echo "
\nError: ". DEFAULT_ERROR ."
\n"; + } + phpCAS :: trace($msg . ' in ' . $file . 'on line ' . $line ); + 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 */ - function trace($str) + public static function trace($str) { - $dbg = phpCAS::backtrace(); - phpCAS::log($str.' ['.basename($dbg[1]['file']).':'.$dbg[1]['line'].']'); + $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. + * This method is used to indicate the start of the execution of a function + * in debug mode. + * + * @return void */ - function traceBegin() + public static function traceBegin() { - global $PHPCAS_DEBUG; - - $dbg = phpCAS::backtrace(); + $dbg = debug_backtrace(); $str = '=> '; - if ( !empty($dbg[2]['class']) ) { - $str .= $dbg[2]['class'].'::'; + if (!empty ($dbg[1]['class'])) { + $str .= $dbg[1]['class'] . '::'; } - $str .= $dbg[2]['function'].'('; - if ( is_array($dbg[2]['args']) ) { - foreach ($dbg[2]['args'] as $index => $arg) { - if ( $index != 0 ) { + $str .= $dbg[1]['function'] . '('; + if (is_array($dbg[1]['args'])) { + foreach ($dbg[1]['args'] as $index => $arg) { + if ($index != 0) { $str .= ', '; } - $str .= str_replace("\n","",var_export($arg,TRUE)); + if (is_object($arg)) { + $str .= get_class($arg); + } else { + $str .= str_replace(array("\r\n", "\n", "\r"), "", var_export($arg, true)); + } } } - $str .= ') ['.basename($dbg[2]['file']).':'.$dbg[2]['line'].']'; - phpCAS::log($str); - $PHPCAS_DEBUG['indent'] ++; + 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. + * This method is used to indicate the end of the execution of a function in + * debug mode. * - * @param $res the result of the function + * @param string $res the result of the function + * + * @return void */ - function traceEnd($res='') + public static function traceEnd($res = '') { - global $PHPCAS_DEBUG; - - $PHPCAS_DEBUG['indent'] --; - $dbg = phpCAS::backtrace(); + if (empty(self::$_PHPCAS_DEBUG['indent'])) { + self::$_PHPCAS_DEBUG['indent'] = 0; + } else { + self::$_PHPCAS_DEBUG['indent']--; + } + $dbg = debug_backtrace(); $str = ''; - $str .= '<= '.str_replace("\n","",var_export($res,TRUE)); - phpCAS::log($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 */ - function traceExit() + public static function traceExit() { - global $PHPCAS_DEBUG; - - phpCAS::log('exit()'); - while ( $PHPCAS_DEBUG['indent'] > 0 ) { - phpCAS::log('-'); - $PHPCAS_DEBUG['indent'] --; + phpCAS :: log('exit()'); + while (self::$_PHPCAS_DEBUG['indent'] > 0) { + phpCAS :: log('-'); + self::$_PHPCAS_DEBUG['indent']--; } } @@ -560,28 +673,29 @@ class phpCAS // INTERNATIONALIZATION // ######################################################################## /** - * @addtogroup publicLang - * @{ - */ + * @addtogroup publicLang + * @{ + */ /** * This method is used to set the language used by phpCAS. - * @note Can be called only once. * - * @param $lang a string representing the language. + * @param string $lang string representing the language. + * + * @return void * * @sa PHPCAS_LANG_FRENCH, PHPCAS_LANG_ENGLISH + * @note Can be called only once. */ - function setLang($lang) + public static function setLang($lang) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setLang($lang); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($lang) != 'string' ) { - phpCAS::error('type mismatched for parameter $lang (should be `string\')'); - } - $PHPCAS_CLIENT->setLang($lang); } /** @} */ @@ -589,16 +703,16 @@ class phpCAS // VERSION // ######################################################################## /** - * @addtogroup public - * @{ - */ + * @addtogroup public + * @{ + */ /** * This method returns the phpCAS version. * * @return the phpCAS version. */ - function getVersion() + public static function getVersion() { return PHPCAS_VERSION; } @@ -608,42 +722,44 @@ class phpCAS // HTML OUTPUT // ######################################################################## /** - * @addtogroup publicOutput - * @{ - */ + * @addtogroup publicOutput + * @{ + */ /** * This method sets the HTML header used for all outputs. * - * @param $header the HTML header. + * @param string $header the HTML header. + * + * @return void */ - function setHTMLHeader($header) + public static function setHTMLHeader($header) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setHTMLHeader($header); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($header) != 'string' ) { - phpCAS::error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLHeader($header); } /** * This method sets the HTML footer used for all outputs. * - * @param $footer the HTML footer. + * @param string $footer the HTML footer. + * + * @return void */ - function setHTMLFooter($footer) + public static function setHTMLFooter($footer) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setHTMLFooter($footer); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($footer) != 'string' ) { - phpCAS::error('type mismatched for parameter $footer (should be `string\')'); - } - $PHPCAS_CLIENT->setHTMLFooter($footer); } /** @} */ @@ -651,195 +767,200 @@ class phpCAS // PGT STORAGE // ######################################################################## /** - * @addtogroup publicPGTStorage - * @{ + * @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(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setPGTStorage($storage); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + 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(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + phpCAS :: traceEnd(); + } /** * 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 - */ - function setPGTStorageFile($format='', - $path='') - { - global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { - 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'].')'); - } - if ( gettype($format) != 'string' ) { - phpCAS::error('type mismatched for parameter $format (should be `string\')'); - } - if ( gettype($path) != 'string' ) { - phpCAS::error('type mismatched for parameter $format (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageFile($format,$path); - phpCAS::traceEnd(); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage, except in debug mode. + * @param string $path the path where the PGT's should be stored * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data + * @return void */ - function setPGTStorageDB($user, - $password, - $database_type='', - $hostname='', - $port=0, - $database='', - $table='') + public static function setPGTStorageFile($path = '') { - global $PHPCAS_CLIENT,$PHPCAS_AUTH_CHECK_CALL; + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + try { + self::$_PHPCAS_CLIENT->setPGTStorageFile($path); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( $PHPCAS_AUTH_CHECK_CALL['done'] ) { - 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'].')'); - } - if ( gettype($user) != 'string' ) { - phpCAS::error('type mismatched for parameter $user (should be `string\')'); - } - if ( gettype($password) != 'string' ) { - phpCAS::error('type mismatched for parameter $password (should be `string\')'); - } - if ( gettype($database_type) != 'string' ) { - phpCAS::error('type mismatched for parameter $database_type (should be `string\')'); - } - if ( gettype($hostname) != 'string' ) { - phpCAS::error('type mismatched for parameter $hostname (should be `string\')'); - } - if ( gettype($port) != 'integer' ) { - phpCAS::error('type mismatched for parameter $port (should be `integer\')'); - } - if ( gettype($database) != 'string' ) { - phpCAS::error('type mismatched for parameter $database (should be `string\')'); - } - if ( gettype($table) != 'string' ) { - phpCAS::error('type mismatched for parameter $table (should be `string\')'); - } - $PHPCAS_CLIENT->setPGTStorageDB($this,$user,$password,$hostname,$port,$database,$table); - phpCAS::traceEnd(); + phpCAS :: traceEnd(); } - /** @} */ // ######################################################################## // ACCESS TO EXTERNAL SERVICES // ######################################################################## /** - * @addtogroup publicServices - * @{ + * @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(); + phpCAS::_validateProxyExists(); + + try { + $res = self::$_PHPCAS_CLIENT->getProxiedService($type); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + 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) + { + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } /** * 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). + * @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 TRUE on success, FALSE otherwise (in this later case, $err_code - * gives the reason why it failed and $output contains an error message). + * @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). */ - function serviceWeb($url,&$err_code,&$output) + public static function serviceWeb($url, & $err_code, & $output) { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - 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 ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - 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'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); + try { + $res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - $res = $PHPCAS_CLIENT->serviceWeb($url,$err_code,$output); - - phpCAS::traceEnd($res); + phpCAS :: traceEnd($res); return $res; } /** * 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 $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). + * @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 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). + * @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). */ - function serviceMail($url,$flags,&$err_code,&$err_msg,&$pt) + public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt) { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - 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 ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - 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'); - } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); + try { + $res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($flags) != 'integer' ) { - phpCAS::error('type mismatched for parameter $flags (should be `integer\')'); - } - - $res = $PHPCAS_CLIENT->serviceMail($url,$flags,$err_code,$err_msg,$pt); - - phpCAS::traceEnd($res); + phpCAS :: traceEnd($res); return $res; } @@ -848,53 +969,100 @@ class phpCAS // AUTHENTICATION // ######################################################################## /** - * @addtogroup publicAuth - * @{ - */ + * @addtogroup publicAuth + * @{ + */ /** - * Set the times authentication will be cached before really accessing the CAS server in gateway mode: + * 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 $n an integer. + * @param int $n an integer. + * + * @return void */ - function setCacheTimesForAuthRecheck($n) + public static function setCacheTimesForAuthRecheck($n) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($n) != 'integer' ) { - phpCAS::error('type mismatched for parameter $header (should be `string\')'); - } - $PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n); } /** - * This method is called to check if the user is authenticated (use the gateway feature). - * @return TRUE when the user is authenticated; otherwise FALSE. + * 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 */ - function checkAuthentication() + public static function setPostAuthenticateCallback ($function, array $additionalArgs = array()) { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + phpCAS::_validateClientExists(); - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } + self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs); + } - $auth = $PHPCAS_CLIENT->checkAuthentication(); + /** + * 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()) + { + phpCAS::_validateClientExists(); + + 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(); + phpCAS::_validateClientExists(); + + $auth = self::$_PHPCAS_CLIENT->checkAuthentication(); // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); - phpCAS::traceEnd($auth); + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + phpCAS :: traceEnd($auth); return $auth; } @@ -902,140 +1070,192 @@ class phpCAS * 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 */ - function forceAuthentication() + public static function forceAuthentication() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - - $auth = $PHPCAS_CLIENT->forceAuthentication(); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + $auth = self::$_PHPCAS_CLIENT->forceAuthentication(); // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); - if ( !$auth ) { - phpCAS::trace('user is not authenticated, redirecting to the CAS server'); - $PHPCAS_CLIENT->forceAuthentication(); + /* 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 :: trace('no need to authenticate (user `' . phpCAS :: getUser() . '\' is already authenticated)'); + }*/ - phpCAS::traceEnd(); + phpCAS :: traceEnd(); return $auth; } /** * This method is called to renew the authentication. + * + * @return void **/ - function renewAuthentication() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + public static function renewAuthentication() + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); - phpCAS::traceBegin(); - if ( !is_object($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 - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, 'file' => $dbg[0]['file'], 'line' => $dbg[0]['line'], 'method' => __CLASS__.'::'.__FUNCTION__, 'result' => $auth ); + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); - $PHPCAS_CLIENT->renewAuthentication(); - phpCAS::traceEnd(); - } - - /** - * This method has been left from version 0.4.1 for compatibility reasons. - */ - function authenticate() - { - phpCAS::error('this method is deprecated. You should use '.__CLASS__.'::forceAuthentication() instead'); + //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. + * @return true when the user is authenticated. */ - function isAuthenticated() + public static function isAuthenticated() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - - // call the isAuthenticated method of the global $PHPCAS_CLIENT object - $auth = $PHPCAS_CLIENT->isAuthenticated(); + // call the isAuthenticated method of the $_PHPCAS_CLIENT object + $auth = self::$_PHPCAS_CLIENT->isAuthenticated(); // store where the authentication has been checked and the result - $dbg = phpCAS::backtrace(); - $PHPCAS_AUTH_CHECK_CALL = array('done' => TRUE, - 'file' => $dbg[0]['file'], - 'line' => $dbg[0]['line'], - 'method' => __CLASS__.'::'.__FUNCTION__, - 'result' => $auth ); - phpCAS::traceEnd($auth); + self::$_PHPCAS_CLIENT->markAuthenticationCall($auth); + + phpCAS :: traceEnd($auth); return $auth; } /** * Checks whether authenticated based on $_SESSION. Useful to avoid * server calls. - * @return true if authenticated, false otherwise. + * + * @return bool true if authenticated, false otherwise. * @since 0.4.22 by Brendan Arnold */ - function isSessionAuthenticated () + public static function isSessionAuthenticated() { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return($PHPCAS_CLIENT->isSessionAuthenticated()); + phpCAS::_validateClientExists(); + + return (self::$_PHPCAS_CLIENT->isSessionAuthenticated()); } /** * This method returns the CAS user's login name. - * @warning should not be called only after phpCAS::forceAuthentication() + * + * @return string the login name of the authenticated user + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * */ + public static function getUser() + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getUser(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * Answer attributes about the authenticated user. + * + * @warning should only be called after phpCAS::forceAuthentication() * or phpCAS::checkAuthentication(). * - * @return the login name of the authenticated user + * @return array */ - function getUser() + public static function getAttributes() { - global $PHPCAS_CLIENT, $PHPCAS_AUTH_CHECK_CALL; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getAttributes(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( !$PHPCAS_AUTH_CHECK_CALL['done'] ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::forceAuthentication() or '.__CLASS__.'::isAuthenticated()'); + } + + /** + * Answer true if there are attributes for the authenticated user. + * + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + * + * @return bool + */ + public static function hasAttributes() + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->hasAttributes(); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( !$PHPCAS_AUTH_CHECK_CALL['result'] ) { - 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'); + } + + /** + * Answer true if an attribute exists for the authenticated user. + * + * @param string $key attribute name + * + * @return bool + * @warning should only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + */ + public static function hasAttribute($key) + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->hasAttribute($key); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + } + + /** + * 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 only be called after phpCAS::forceAuthentication() + * or phpCAS::checkAuthentication(). + */ + public static function getAttribute($key) + { + phpCAS::_validateClientExists(); + + try { + return self::$_PHPCAS_CLIENT->getAttribute($key); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - return $PHPCAS_CLIENT->getUser(); } /** * Handle logout requests. + * + * @param bool $check_client additional safety check + * @param array $allowed_clients array of allowed clients + * + * @return void */ - function handleLogoutRequests($check_client=true, $allowed_clients=false) + public static function handleLogoutRequests($check_client = true, $allowed_clients = false) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return($PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients)); + phpCAS::_validateClientExists(); + + return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients)); } /** @@ -1044,34 +1264,98 @@ class phpCAS * * @return the login name of the authenticated user */ - function getServerLoginURL() + public static function getServerLoginURL() { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return $PHPCAS_CLIENT->getServerLoginURL(); + phpCAS::_validateClientExists(); + + return self::$_PHPCAS_CLIENT->getServerLoginURL(); } /** * Set the login URL of the CAS server. - * @param $url the login URL + * + * @param string $url the login URL + * + * @return void * @since 0.4.21 by Wyman Chan */ - function setServerLoginURL($url='') + public static function setServerLoginURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after - '.__CLASS__.'::client()'); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerLoginURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be - `string\')'); + + 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(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - $PHPCAS_CLIENT->setServerLoginURL($url); - phpCAS::traceEnd(); + + 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(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + 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(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); } /** @@ -1080,245 +1364,279 @@ class phpCAS * * @return the login name of the authenticated user */ - function getServerLogoutURL() + public static function getServerLogoutURL() { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should not be called before '.__CLASS__.'::client() or '.__CLASS__.'::proxy()'); - } - return $PHPCAS_CLIENT->getServerLogoutURL(); + phpCAS::_validateClientExists(); + + return self::$_PHPCAS_CLIENT->getServerLogoutURL(); } /** * Set the logout URL of the CAS server. - * @param $url the logout URL + * + * @param string $url the logout URL + * + * @return void * @since 0.4.21 by Wyman Chan */ - function setServerLogoutURL($url='') + public static function setServerLogoutURL($url = '') { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after - '.__CLASS__.'::client()'); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->setServerLogoutURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be - `string\')'); - } - $PHPCAS_CLIENT->setServerLogoutURL($url); - phpCAS::traceEnd(); + + phpCAS :: traceEnd(); } /** * 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 + * + * @param string $params an array that contains the optional url and + * service parameters that will be passed to the CAS server + * + * @return void */ - function logout($params = "") { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if (!is_object($PHPCAS_CLIENT)) { - phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); - } - $parsedParams = array(); + public static function logout($params = "") + { + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + $parsedParams = array (); if ($params != "") { if (is_string($params)) { - phpCAS::error('method `phpCAS::logout($url)\' is now deprecated, use `phpCAS::logoutWithUrl($url)\' instead'); + 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\')'); + 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)\''); + phpCAS :: error('only `url\' and `service\' parameters are allowed for method `phpCAS::logout($params)\''); } $parsedParams[$key] = $value; } } - $PHPCAS_CLIENT->logout($parsedParams); + self::$_PHPCAS_CLIENT->logout($parsedParams); // never reached - phpCAS::traceEnd(); + phpCAS :: traceEnd(); } /** - * This method is used to logout from CAS. Halts by redirecting to the CAS server. - * @param $service a URL that will be transmitted to the CAS server - */ - function logoutWithRedirectService($service) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($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\')'); - } - $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 $url a URL that will be transmitted to the CAS server - */ - function logoutWithUrl($url) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($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\')'); - } - $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 $service a URL that will be transmitted to the CAS server - * @param $url a URL that will be transmitted to the CAS server - */ - function logoutWithRedirectServiceAndUrl($service, $url) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($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\')'); - } - $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. + * This method is used to logout from CAS. Halts by redirecting to the CAS + * server. * - * @param $url the URL + * @param string $service a URL that will be transmitted to the CAS server + * + * @return void */ - function setFixedCallbackURL($url='') + public static function logoutWithRedirectService($service) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + if (!is_string($service)) { + phpCAS :: error('type mismatched for parameter $service (should be `string\')'); } - if ( !$PHPCAS_CLIENT->isProxy() ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + 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 ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); + if (!is_string($url)) { + phpCAS :: error('type mismatched for parameter $url (should be `string\')'); } - $PHPCAS_CLIENT->setCallbackURL($url); - phpCAS::traceEnd(); + 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(); + phpCAS::_validateClientExists(); + + 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(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setCallbackURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + 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 $url the URL + * @param string $url the URL + * + * @return void */ - function setFixedServiceURL($url) + public static function setFixedServiceURL($url) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + phpCAS :: traceBegin(); + phpCAS::_validateProxyExists(); + + try { + self::$_PHPCAS_CLIENT->setURL($url); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($url) != 'string' ) { - phpCAS::error('type mismatched for parameter $url (should be `string\')'); - } - $PHPCAS_CLIENT->setURL($url); - phpCAS::traceEnd(); + + phpCAS :: traceEnd(); } /** * Get the URL that is set as the CAS service parameter. + * + * @return string Service Url */ - function getServiceURL() + public static function getServiceURL() { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); - } - return($PHPCAS_CLIENT->getURL()); + phpCAS::_validateProxyExists(); + 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 */ - function retrievePT($target_service,&$err_code,&$err_msg) + public static function retrievePT($target_service, & $err_code, & $err_msg) { - global $PHPCAS_CLIENT; - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::proxy()'); + phpCAS::_validateProxyExists(); + + try { + return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg)); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($target_service) != 'string' ) { - phpCAS::error('type mismatched for parameter $target_service(should be `string\')'); - } - return($PHPCAS_CLIENT->retrievePT($target_service,$err_code,$err_msg)); } /** - * Set the certificate of the CAS server. + * Set the certificate of the CAS server CA and if the CN should be properly + * verified. * - * @param $cert the PEM certificate + * @param string $cert CA certificate file name + * @param bool $validate_cn Validate CN in certificate (default true) + * + * @return void */ - function setCasServerCert($cert) + public static function setCasServerCACert($cert, $validate_cn = true) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($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\')'); - } - $PHPCAS_CLIENT->setCasServerCert($cert); - phpCAS::traceEnd(); - } + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); - /** - * Set the certificate of the CAS server CA. - * - * @param $cert the CA certificate - */ - function setCasServerCACert($cert) - { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); + try { + self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); } - if ( gettype($cert) != 'string' ) { - phpCAS::error('type mismatched for parameter $cert (should be `string\')'); - } - $PHPCAS_CLIENT->setCasServerCACert($cert); - phpCAS::traceEnd(); + + phpCAS :: traceEnd(); } /** * Set no SSL validation for the CAS server. + * + * @return void */ - function setNoCasServerValidation() + public static function setNoCasServerValidation() { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); - } - $PHPCAS_CLIENT->setNoCasServerValidation(); - phpCAS::traceEnd(); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + 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(); + phpCAS::_validateClientExists(); + + self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl(); + phpCAS :: traceEnd(); } /** @} */ @@ -1326,22 +1644,164 @@ class phpCAS /** * Change CURL options. * CURL is used to connect through HTTPS to CAS server - * @param $key the option key - * @param $value the value to set + * + * @param string $key the option key + * @param string $value the value to set + * + * @return void */ - function setExtraCurlOption($key, $value) + public static function setExtraCurlOption($key, $value) { - global $PHPCAS_CLIENT; - phpCAS::traceBegin(); - if ( !is_object($PHPCAS_CLIENT) ) { - phpCAS::error('this method should only be called after '.__CLASS__.'::client() or'.__CLASS__.'::proxy()'); + phpCAS :: traceBegin(); + phpCAS::_validateClientExists(); + + 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(); + phpCAS::_validateClientExists(); + + if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0 + && self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0 + ) { + phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols'); } - $PHPCAS_CLIENT->setExtraCurlOption($key, $value); + 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 () + { + phpCAS::_validateProxyExists(); + + 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); + phpCAS::_validateClientExists(); + + try { + self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + 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(); + phpCAS::_validateClientExists(); + try { + self::$_PHPCAS_CLIENT->addRebroadcastHeader($header); + } catch (Exception $e) { + phpCAS :: error(get_class($e) . ': ' . $e->getMessage()); + } + + phpCAS :: traceEnd(); + } + + /** + * Checks if a client already exists + * + * @throws CAS_OutOfSequenceBeforeClientException + * + * @return void + */ + private static function _validateClientExists() + { + if (!is_object(self::$_PHPCAS_CLIENT)) { + throw new CAS_OutOfSequenceBeforeClientException(); + } + } + + /** + * Checks of a proxy client aready exists + * + * @throws CAS_OutOfSequenceBeforeProxyException + * + * @return void + */ + private static function _validateProxyExists() + { + if (!is_object(self::$_PHPCAS_CLIENT)) { + throw new CAS_OutOfSequenceBeforeProxyException(); + } + } +} // ######################################################################## // DOCUMENTATION // ######################################################################## @@ -1385,7 +1845,6 @@ class phpCAS /** @defgroup publicDebug Debugging * @ingroup public */ - /** @defgroup internal Implementation */ /** @defgroup internalAuthentication Authentication @@ -1397,10 +1856,13 @@ class phpCAS /** @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 +/** @defgroup internalPGTStorageDb PGT storage in a database * @ingroup internalPGTStorage */ /** @defgroup internalPGTStorageFile PGT storage on the filesystem @@ -1409,12 +1871,18 @@ class phpCAS /** @defgroup internalCallback Callback from the CAS server * @ingroup internalProxy */ -/** @defgroup internalProxied CAS proxied client features (CAS 2.0, Proxy Tickets) +/** @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 */ @@ -1440,10 +1908,25 @@ class phpCAS * @example example_simple.php */ /** - * @example example_proxy.php + * @example example_service.php */ /** - * @example example_proxy2.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 @@ -1452,24 +1935,24 @@ class phpCAS * @example example_html.php */ /** - * @example example_file.php + * @example example_pgt_storage_file.php */ /** - * @example example_db.php - */ -/** - * @example example_service.php - */ -/** - * @example example_session_proxy.php - */ -/** - * @example example_session_service.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/include/limesurvey/admin/classes/phpCAS/CAS/AuthenticationException.php b/include/limesurvey/admin/classes/phpCAS/CAS/AuthenticationException.php new file mode 100644 index 00000000..a14154d4 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/AuthenticationException.php @@ -0,0 +1,108 @@ + + * @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 + * @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()), + isset($_SERVER['SERVER_ADMIN']) ? $_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: + case CAS_VERSION_3_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/include/limesurvey/admin/classes/phpCAS/CAS/Autoload.php b/include/limesurvey/admin/classes/phpCAS/CAS/Autoload.php new file mode 100644 index 00000000..e56dbdfa --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Autoload.php @@ -0,0 +1,105 @@ + + * @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; + // Check only for CAS classes + if (substr($class, 0, 4) !== 'CAS_') { + return false; + } + // Setup the include path if it's not already set from a previous call + if (empty($include_path)) { + $include_path = array(dirname(dirname(__FILE__)), dirname(dirname(__FILE__)) . '/../test/' ); + } + + // Declare local variable to store the expected full path to the file + + foreach ($include_path as $path) { + $file_path = $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="' + . implode(':', $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/include/limesurvey/admin/classes/phpCAS/CAS/Client.php b/include/limesurvey/admin/classes/phpCAS/CAS/Client.php new file mode 100644 index 00000000..7282e288 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Client.php @@ -0,0 +1,3867 @@ + + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @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 + * @author Olivier Berger + * @author Brett Bieber + * @author Joachim Fritschi + * @author Adam Franco + * @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) + ? '__TITLE__

__TITLE__

' + : $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)? + (phpcas::getVerbose())? + '
phpCAS __PHPCAS_VERSION__ ' + .$lang->getUsingServer() + .' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
' + :'' + :$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) + { + // Argument Validation + if (gettype($header) != 'string') + throw new CAS_TypeMismatchException($header, '$header', 'string'); + + $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) + { + // Argument Validation + if (gettype($footer) != 'string') + throw new CAS_TypeMismatchException($footer, '$footer', 'string'); + + $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) + { + // Argument Validation + if (gettype($lang) != 'string') + throw new CAS_TypeMismatchException($lang, '$lang', 'string'); + + 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->_buildQueryUrl($this->_getServerBaseURL().'login','service='.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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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; + case CAS_VERSION_3_0: + $this->_server['service_validate_url'] = $this->_getServerBaseURL() + .'p3/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; + case CAS_VERSION_3_0: + $this->_server['proxy_validate_url'] = $this->_getServerBaseURL().'p3/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: + case CAS_VERSION_3_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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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. + // ######################################################################## + + /** + * Ensure that this is actually a proxy object or fail with an exception + * + * @throws CAS_OutOfSequenceBeforeProxyException + * + * @return void + */ + public function ensureIsProxy() + { + if (!$this->isProxy()) { + throw new CAS_OutOfSequenceBeforeProxyException(); + } + } + + /** + * 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); + } + + /** + * Ensure that authentication was checked. Terminate with exception if no + * authentication was performed + * + * @throws CAS_OutOfSequenceBeforeAuthenticationCallException + * + * @return void + */ + private function _ensureAuthenticationCalled() + { + if (!$this->wasAuthenticationCalled()) { + throw new CAS_OutOfSequenceBeforeAuthenticationCallException(); + } + } + + /** + * 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 () + { + $this->_ensureAuthenticationCalled(); + return $this->_authentication_caller['result']; + } + + + /** + * Ensure that authentication was checked. Terminate with exception if no + * authentication was performed + * + * @throws CAS_OutOfSequenceBeforeAuthenticationCallException + * + * @return void + */ + public function ensureAuthenticationCallSuccessful() + { + $this->_ensureAuthenticationCalled(); + if (!$this->_authentication_caller['result']) { + throw new CAS_OutOfSequenceException( + 'authentication was checked (by ' + . $this->getAuthenticationCallerMethod() + . '() at ' . $this->getAuthenticationCallerFile() + . ':' . $this->getAuthenticationCallerLine() + . ') but the method returned false' + ); + } + } + + /** + * 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 () + { + $this->_ensureAuthenticationCalled(); + 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 () + { + $this->_ensureAuthenticationCalled(); + 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 () + { + $this->_ensureAuthenticationCalled(); + 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 + ) { + // Argument validation + if (gettype($server_version) != 'string') + throw new CAS_TypeMismatchException($server_version, '$server_version', 'string'); + if (gettype($proxy) != 'boolean') + throw new CAS_TypeMismatchException($proxy, '$proxy', 'boolean'); + if (gettype($server_hostname) != 'string') + throw new CAS_TypeMismatchException($server_hostname, '$server_hostname', 'string'); + if (gettype($server_port) != 'integer') + throw new CAS_TypeMismatchException($server_port, '$server_port', 'integer'); + if (gettype($server_uri) != 'string') + throw new CAS_TypeMismatchException($server_uri, '$server_uri', 'string'); + if (gettype($changeSessionID) != 'boolean') + throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean'); + + phpCAS::traceBegin(); + // true : allow to change the session_id(), false session_id won't be + // change and logout won't be handle because of that + $this->_setChangeSessionID($changeSessionID); + + // skip Session Handling for logout requests and if don't want it' + if (session_id()=="" && !$this->_isLogoutRequest()) { + session_start(); + phpCAS :: trace("Starting a new session " . session_id()); + } + + // 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: + case CAS_VERSION_3_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 + if(strstr($server_uri, '?') === false) $server_uri .= '/'; + $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() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + return $this->_getUser(); + } + + /** + * 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. + */ + private function _getUser() + { + // This is likely a duplicate check that could be removed.... + 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() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + // This is likely a duplicate check that could be removed.... + 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() + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + 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) + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + return $this->_hasAttribute($key); + } + + /** + * Check whether a specific attribute with a name is available + * + * @param string $key name of attribute + * + * @return bool is attribute available + */ + private 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) + { + // Sequence validation + $this->ensureAuthenticationCallSuccessful(); + + 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 true when the user is authenticated; otherwise halt. + */ + 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(true) ) { + phpCAS::trace('user already authenticated'); + $res = true; + } else { + $this->redirectToCas(false, true); + // never reached + $res = false; + } + phpCAS::traceEnd(); + return $res; + } + + /** + * 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) + { + if (gettype($n) != 'integer') + throw new CAS_TypeMismatchException($n, '$n', 'string'); + + $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). + * + * @param bool $renew true to force the authentication with the CAS server + * + * @return true when the user is authenticated. Also may redirect to the + * same URL without the ticket. + */ + public function isAuthenticated($renew=false) + { + 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()); + session_write_close(); + 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; + } + + // Mark the auth-check as complete to allow post-authentication + // callbacks to make use of phpCAS::getUser() and similar methods + $this->markAuthenticationCall($res); + } 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, $renew + ); // 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: + case CAS_VERSION_3_0: + // if a Proxy Ticket was given, validate it + phpCAS::trace( + 'CAS '.$this->getServerVersion().' ticket `'.$this->getTicket().'\' is present' + ); + $this->validateCAS20( + $validate_url, $text_response, $tree_response, $renew + ); // note: if it fails, it halts + phpCAS::trace( + 'CAS '.$this->getServerVersion().' 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 (!empty($this->_attributes)) { + $_SESSION['phpCAS']['attributes'] = $this->_attributes; + } + $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, $renew + ); // if it fails, it halts + phpCAS::trace( + 'SAML 1.1 ticket `'.$this->getTicket().'\' was validated' + ); + $_SESSION['phpCAS']['user'] = $this->_getUser(); + $_SESSION['phpCAS']['attributes'] = $this->_attributes; + $res = true; + $logoutTicket = $this->getTicket(); + break; + default: + phpCAS::trace('Protocoll error'); + break; + } + } else { + // no ticket given, not authenticated + phpCAS::trace('no ticket found'); + } + + // Mark the auth-check as complete to allow post-authentication + // callbacks to make use of phpCAS::getUser() and similar methods + $this->markAuthenticationCall($res); + + if ($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()); + session_write_close(); + 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); + session_write_close(); + 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('

'. $lang->getShouldHaveBeenRedirected(). '

', $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('

'.$lang->getShouldHaveBeenRedirected(). '

', $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) + || ($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( + "|(.*)|", + $decoded_logout_rq, $tick, PREG_OFFSET_CAPTURE, 3 + ); + $wrappedSamlSessionIndex = preg_replace( + '||', '', $tick[0][0] + ); + $ticket2logout = preg_replace( + '||', '', $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; + + + /** + + * validate CN of the CAS server certificate + + * + + * @hideinitializer + + */ + + 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) + { + // Argument validation + if (gettype($cert) != 'string') + throw new CAS_TypeMismatchException($cert, '$cert', 'string'); + if (gettype($validate_cn) != 'boolean') + throw new CAS_TypeMismatchException($validate_cn, '$validate_cn', 'boolean'); + + $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. + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + */ + public function validateCAS10(&$validate_url,&$text_response,&$tree_response,$renew=false) + { + phpCAS::traceBegin(); + $result = false; + // build the URL to validate the ticket + $validate_url = $this->getServerServiceValidateURL() + .'&ticket='.urlencode($this->getTicket()); + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // 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. + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + */ + public function validateSA(&$validate_url,&$text_response,&$tree_response,$renew=false) + { + phpCAS::traceBegin(); + $result = false; + // build the URL to validate the ticket + $validate_url = $this->getServerSamlValidateURL(); + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // 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 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 . "=" . print_r($attr_value, true)); + } 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->_getClientUrl(); + $request_uri = $_SERVER['REQUEST_URI']; + $request_uri = preg_replace('/\?.*$/', '', $request_uri); + $final_uri .= $request_uri; + $this->_callback_url = $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) + { + // Sequence validation + $this->ensureIsProxy(); + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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 '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; + $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) + { + // Sequence validation + $this->ensureIsProxy(); + + // 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) ) + throw new CAS_TypeMismatchException($storage, '$storage', 'CAS_PGTStorage_AbstractStorage 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 + ) { + // Sequence validation + $this->ensureIsProxy(); + + // Argument validation + if ((is_object($dsn_or_pdo) && !($dsn_or_pdo instanceof PDO)) || gettype($dsn_or_pdo) != 'string') + throw new CAS_TypeMismatchException($dsn_or_pdo, '$dsn_or_pdo', 'string or PDO object'); + if (gettype($username) != 'string') + throw new CAS_TypeMismatchException($username, '$username', 'string'); + if (gettype($password) != 'string') + throw new CAS_TypeMismatchException($password, '$password', 'string'); + if (gettype($table) != 'string') + throw new CAS_TypeMismatchException($table, '$password', 'string'); + + // 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='') + { + // Sequence validation + $this->ensureIsProxy(); + + // Argument validation + if (gettype($path) != 'string') + throw new CAS_TypeMismatchException($path, '$path', 'string'); + + // 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(' 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) + { + // Argument validation + if (gettype($target_service) != 'string') + throw new CAS_TypeMismatchException($target_service, '$target_service', 'string'); + + 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(' was found, but not '); + } + } 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 nor 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 = urlencode($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) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($type) != 'string') + throw new CAS_TypeMismatchException($type, '$type', 'string'); + + 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) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + $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) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + 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) + { + // Sequence validation + $this->ensureIsProxy(); + $this->ensureAuthenticationCallSuccessful(); + + // Argument validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + if (gettype($serviceUrl) != 'string') + throw new CAS_TypeMismatchException($serviceUrl, '$serviceUrl', 'string'); + if (gettype($flags) != 'integer') + throw new CAS_TypeMismatchException($flags, '$flags', 'string'); + + 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 + * @param bool $renew true to force the authentication with the CAS server + * + * @return bool true when successfull and issue a CAS_AuthenticationException + * and false on an error + */ + public function validateCAS20(&$validate_url,&$text_response,&$tree_response, $renew=false) + { + phpCAS::traceBegin(); + phpCAS::trace($text_response); + $result = false; + // build the URL to validate the ticket + if ($this->getAllowedProxyChains()->isProxyingAllowed()) { + $validate_url = $this->getServerProxyValidateURL().'&ticket=' + .urlencode($this->getTicket()); + } else { + $validate_url = $this->getServerServiceValidateURL().'&ticket=' + .urlencode($this->getTicket()); + } + + if ( $this->isProxy() ) { + // pass the callback url for CAS proxies + $validate_url .= '&pgtUrl='.urlencode($this->_getCallbackURL()); + } + + if ( $renew ) { + // pass the renew + $validate_url .= '&renew=true'; + } + + // 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: + // + // + // + // jsmith + // + // RubyCAS + // Smith + // John + // CN=Staff,OU=Groups,DC=example,DC=edu + // CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + 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 + // + // + // + // jsmith + // + // RubyCAS + // Smith + // John + // CN=Staff,OU=Groups,DC=example,DC=edu + // CN=Spanish Department,OU=Departments,OU=Groups,DC=example,DC=edu + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + 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. + // + // + // + // jsmith + // + // + // + // + // + // + // + // PGTIOU-84678-8a9d2sfa23casd + // + // + // + 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) + { + // Argument Validation + if (gettype($url) != 'string') + throw new CAS_TypeMismatchException($url, '$url', 'string'); + + $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->_getClientUrl(); + $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 phpCas client URL with possible Proxys / Ports etc. + * + * @return string Server URL with domain:port + */ + private function _getClientUrl() + { + $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']); + // see rfc7239#5.3 and rfc7230#2.7.1: port is in HTTP_X_FORWARDED_HOST if non default + return $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 { + $ports = explode(',', $_SERVER['HTTP_X_FORWARDED_PORT']); + $server_port = $ports[0]; + } + + 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 (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); + } + if ( isset($_SERVER['HTTPS']) + && !empty($_SERVER['HTTPS']) + && strcasecmp($_SERVER['HTTPS'], 'off') !== 0 + ) { + 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; + phpCAS :: trace("Killing session: ". session_id()); + session_destroy(); + // set up a new session, of name based on the ticket + $session_id = preg_replace('/[^a-zA-Z0-9\-]/', '', $ticket); + phpCAS :: trace("Starting session: ". $session_id); + session_id($session_id); + session_start(); + phpCAS :: trace("Restoring old session vars"); + $_SESSION = $old_session; + } else { + phpCAS :: trace ( + '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()), + isset($_SERVER['SERVER_ADMIN']) ? $_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: + case CAS_VERSION_3_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) + { + // Argument validation + if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) + throw new CAS_TypeMismatchException($rebroadcastNodeUrl, '$rebroadcastNodeUrl', 'url'); + + // 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) + { + if (gettype($header) != 'string') + throw new CAS_TypeMismatchException($header, '$header', 'string'); + + $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/include/limesurvey/admin/classes/phpCAS/CAS/CookieJar.php b/include/limesurvey/admin/classes/phpCAS/CAS/CookieJar.php new file mode 100644 index 00000000..549b8929 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/CookieJar.php @@ -0,0 +1,385 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Exception.php b/include/limesurvey/admin/classes/phpCAS/CAS/Exception.php new file mode 100644 index 00000000..d956d197 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Exception.php @@ -0,0 +1,59 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/GracefullTerminationException.php b/include/limesurvey/admin/classes/phpCAS/CAS/GracefullTerminationException.php new file mode 100644 index 00000000..6d845dfa --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/GracefullTerminationException.php @@ -0,0 +1,86 @@ + + * @author Adam Franco + * @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 + * @author Adam Franco + * @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/include/limesurvey/admin/classes/phpCAS/CAS/InvalidArgumentException.php b/include/limesurvey/admin/classes/phpCAS/CAS/InvalidArgumentException.php new file mode 100644 index 00000000..ba43d39f --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/InvalidArgumentException.php @@ -0,0 +1,46 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Catalan.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Catalan.php new file mode 100644 index 00000000..a0b64d8e --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Catalan.php @@ -0,0 +1,114 @@ + + * @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à + * @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 aquí 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 '

No estàs autentificat.

Pots tornar a intentar-ho fent click aquí.

Si el problema persisteix hauría de contactar amb l\'administrador d\'aquest llocc.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'El servei `%s\' no està disponible (%s).'; + } +} diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/English.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/English.php new file mode 100644 index 00000000..002c1ba4 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/English.php @@ -0,0 +1,114 @@ + + * @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 + * @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 here 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 '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'The service `%s\' is not available (%s).'; + } +} \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/French.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/French.php new file mode 100644 index 00000000..b99847a7 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/French.php @@ -0,0 +1,116 @@ + + * @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 + * @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 !'; + } + + /** + * Get logout string + * + * @return string logout + */ + public function getLogout() + { + return 'Déconnexion demandée !'; + } + + /** + * 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 ici pour continuer.'; + } + + /** + * Get authentication failed string + * + * @return string authentication failed + */ + public function getAuthenticationFailed() + { + return 'Authentification CAS infructueuse !'; + } + + /** + * Get the your were not authenticated string + * + * @return string not authenticated + */ + public function getYouWereNotAuthenticated() + { + return '

Vous n\'avez pas été authentifié(e).

Vous pouvez soumettre votre requete à nouveau en cliquant ici.

Si le problème persiste, vous pouvez contacter l\'administrateur de ce site.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Le service `%s\' est indisponible (%s)'; + } +} + +?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/German.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/German.php new file mode 100644 index 00000000..ed3150a8 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/German.php @@ -0,0 +1,116 @@ + + * @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 + * @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äten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier 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 '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontaktieren Sie den Administrator dieser Seite.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Der Dienst `%s\' ist nicht verfügbar (%s).'; + } +} + +?> diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Greek.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Greek.php new file mode 100644 index 00000000..eb0f5efe --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Greek.php @@ -0,0 +1,115 @@ + + * @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 + * @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. ÊÜíôå êëßê åäþ ãéá íá óõíå÷ßóåôå.'; + } + + /** + * 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 '

Äåí ôáõôïðïéçèÞêáôå.

Ìðïñåßôå íá îáíáðñïóðáèÞóåôå, êÜíïíôáò êëßê åäþ.

Åáí ôï ðñüâëçìá åðéìåßíåé, åëÜôå óå åðáöÞ ìå ôïí äéá÷åéñéóôÞ.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'Ç õðçñåóßá `%s\' äåí åßíáé äéáèÝóéìç (%s).'; + } +} +?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Japanese.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Japanese.php new file mode 100644 index 00000000..e9cd121e --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Japanese.php @@ -0,0 +1,113 @@ + + * @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 + * @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�����Ф˹Ԥ�ɬ�פ�����ޤ�����ưŪ��ž������ʤ����� ������ �򥯥�å�����³�Ԥ��ޤ��'; + } + + /** + * 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 '

ǧ�ڤǤ��ޤ���Ǥ���.

�⤦���٥ꥯ�����Ȥ�������������������򥯥�å�.

���꤬��褷�ʤ����� ���Υ����Ȥδ�������䤤��碌�Ƥ�������.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return '�����ӥ� `%s\' �����ѤǤ��ޤ��� (%s).'; + } +} +?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/Languages/LanguageInterface.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/LanguageInterface.php new file mode 100644 index 00000000..5de93aa7 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/LanguageInterface.php @@ -0,0 +1,96 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Spanish.php b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Spanish.php new file mode 100644 index 00000000..5675a41d --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Languages/Spanish.php @@ -0,0 +1,117 @@ + + * @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à + * @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 aquí 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 '

No estás autentificado.

Puedes volver a intentarlo haciendo click aquí.

Si el problema persiste debería contactar con el administrador de este sitio.

'; + } + + /** + * Get the service unavailable string + * + * @return string service unavailable + */ + public function getServiceUnavailable() + { + return 'El servicio `%s\' no está disponible (%s).'; + } +} +?> diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeAuthenticationCallException.php b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeAuthenticationCallException.php new file mode 100644 index 00000000..ef830979 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeAuthenticationCallException.php @@ -0,0 +1,56 @@ + + * @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. In this case it should be thrown when an + * authentication call has not yet happened. + * + * @class CAS_OutOfSequenceBeforeAuthenticationCallException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeAuthenticationCallException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + /** + * Return standard error meessage + * + * @return void + */ + public function __construct () + { + parent::__construct('An authentication call hasn\'t happened yet.'); + } +} diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeClientException.php b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeClientException.php new file mode 100644 index 00000000..f1ea7e24 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeClientException.php @@ -0,0 +1,58 @@ + + * @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. In this case it should be thrown when the client() or + * proxy() call has not yet happened and no client or proxy object exists. + * + * @class CAS_OutOfSequenceBeforeClientException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeClientException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + /** + * Return standard error message + * + * @return void + */ + public function __construct () + { + parent::__construct( + 'this method cannot be called before phpCAS::client() or phpCAS::proxy()' + ); + } +} diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeProxyException.php b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeProxyException.php new file mode 100644 index 00000000..8038542e --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceBeforeProxyException.php @@ -0,0 +1,59 @@ + + * @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. In this case it should be thrown when the proxy() call + * has not yet happened and no proxy object exists. + * + * @class CAS_OutOfSequenceBeforeProxyException + * @category Authentication + * @package PhpCAS + * @author Joachim Fritschi + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_OutOfSequenceBeforeProxyException +extends CAS_OutOfSequenceException +implements CAS_Exception +{ + + /** + * Return standard error message + * + * @return void + */ + public function __construct () + { + parent::__construct( + 'this method cannot be called before phpCAS::proxy()' + ); + } +} diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceException.php b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceException.php new file mode 100644 index 00000000..d101811b --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/OutOfSequenceException.php @@ -0,0 +1,49 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-main.php b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/AbstractStorage.php similarity index 60% rename from include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-main.php rename to include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/AbstractStorage.php index c7abff37..c1648984 100644 --- a/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-main.php +++ b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/AbstractStorage.php @@ -1,21 +1,49 @@ + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS */ /** - * @class PGTStorage - * The PGTStorage class is a generic class for PGT storage. This class should - * not be instanciated itself but inherited by specific PGT storage classes. + * 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. * - * @author Pascal Aubry + * @class CAS_PGTStorage_AbstractStorage + * @category Authentication + * @package PhpCAS + * @author Pascal Aubry + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS * * @ingroup internalPGTStorage */ -class PGTStorage +abstract class CAS_PGTStorage_AbstractStorage { /** * @addtogroup internalPGTStorage @@ -29,15 +57,20 @@ class PGTStorage /** * The constructor of the class, should be called only by inherited classes. * - * @param $cas_parent the CASclient instance that creates the current object. + * @param CAS_Client $cas_parent the CAS _client instance that creates the + * current object. + * + * @return void * * @protected */ - function PGTStorage($cas_parent) + 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::error( + 'defining PGT storage makes no sense when not using a CAS proxy' + ); } phpCAS::traceEnd(); } @@ -50,6 +83,8 @@ class PGTStorage * 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() @@ -61,6 +96,8 @@ class PGTStorage * This virtual method returns an informational string giving informations on the * parameters of the storage.(used for debugging purposes). * + * @return void + * * @public */ function getStorageInfo() @@ -73,22 +110,22 @@ class PGTStorage // ######################################################################## /** - * string used to store an error message. Written by PGTStorage::setErrorMessage(), - * read by PGTStorage::getErrorMessage(). + * string used to store an error message. Written by + * PGTStorage::setErrorMessage(), read by PGTStorage::getErrorMessage(). * * @hideinitializer - * @private * @deprecated not used. */ - var $_error_message=FALSE; + var $_error_message=false; /** * This method sets en error message, which can be read later by * PGTStorage::getErrorMessage(). * - * @param $error_message an error message + * @param string $error_message an error message + * + * @return void * - * @protected * @deprecated not used. */ function setErrorMessage($error_message) @@ -102,7 +139,6 @@ class PGTStorage * @return an error message when set by PGTStorage::setErrorMessage(), FALSE * otherwise. * - * @public * @deprecated not used. */ function getErrorMessage() @@ -119,9 +155,8 @@ class PGTStorage * PGTStorage::init(), read by PGTStorage::isInitialized(). * * @hideinitializer - * @private */ - var $_initialized = FALSE; + var $_initialized = false; /** * This method tells if the storage has already been intialized. @@ -138,11 +173,11 @@ class PGTStorage /** * This virtual method initializes the object. * - * @protected + * @return void */ function init() { - $this->_initialized = TRUE; + $this->_initialized = true; } // ######################################################################## @@ -151,12 +186,14 @@ class PGTStorage /** * 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. * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou - * - * @protected */ function write($pgt,$pgt_iou) { @@ -166,11 +203,12 @@ class PGTStorage /** * 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. - * - * @param $pgt_iou the PGT iou - * - * @protected */ function read($pgt_iou) { @@ -181,8 +219,4 @@ class PGTStorage } -// include specific PGT storage classes -include_once(dirname(__FILE__).'/pgt-file.php'); -include_once(dirname(__FILE__).'/pgt-db.php'); - -?> \ No newline at end of file +?> diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/Db.php b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/Db.php new file mode 100644 index 00000000..c331ca09 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/Db.php @@ -0,0 +1,440 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-file.php b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/File.php similarity index 52% rename from include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-file.php rename to include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/File.php index a1f2f694..80a1ea1f 100644 --- a/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-file.php +++ b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/File.php @@ -1,22 +1,48 @@ + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS */ /** - * @class PGTStorageFile - * The PGTStorageFile class is a class for PGT file storage. An instance of - * this class is returned by CASClient::SetPGTStorageFile(). + * 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 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS * - * @author Pascal Aubry * * @ingroup internalPGTStorageFile */ -if (!defined('PHPCAS_VERSION')) die(); -class PGTStorageFile extends PGTStorage +class CAS_PGTStorage_File extends CAS_PGTStorage_AbstractStorage { /** * @addtogroup internalPGTStorageFile @@ -44,26 +70,6 @@ class PGTStorageFile extends PGTStorage return $this->_path; } - /** - * a string telling the format to use to store PGT's (plain or xml). Written by - * PGTStorageFile::PGTStorageFile(), read by getFormat(). - * - * @private - */ - var $_format; - - /** - * This method returns the format to use when storing PGT's on the filesystem. - * - * @return a string corresponding to the format used (plain or xml). - * - * @private - */ - function getFormat() - { - return $this->_format; - } - // ######################################################################## // DEBUGGING // ######################################################################## @@ -89,7 +95,7 @@ class PGTStorageFile extends PGTStorage */ function getStorageInfo() { - return 'path=`'.$this->getPath().'\', format=`'.$this->getFormat().'\''; + return 'path=`'.$this->getPath().'\''; } // ######################################################################## @@ -97,53 +103,43 @@ class PGTStorageFile extends PGTStorage // ######################################################################## /** - * The class constructor, called by CASClient::SetPGTStorageFile(). + * The class constructor, called by CAS_Client::SetPGTStorageFile(). * - * @param $cas_parent the CASClient instance that creates the object. - * @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 + * @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 PGTStorageFile($cas_parent,$format,$path) + function __construct($cas_parent,$path) { phpCAS::traceBegin(); // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if (empty($format) ) $format = CAS_PGT_STORAGE_FILE_DEFAULT_FORMAT; - if (empty($path) ) $path = CAS_PGT_STORAGE_FILE_DEFAULT_PATH; + 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 (getenv("OS")=="Windows_NT") { if (!preg_match('`^[a-zA-Z]:`', $path)) { phpCAS::error('an absolute path is needed for PGT storage to file'); } - } - else - { + } 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); + $path = preg_replace('|[/]*$|', '/', $path); + $path = preg_replace('|^[/]*|', '/', $path); } $this->_path = $path; - // check the format and store it - switch ($format) { - case CAS_PGT_STORAGE_FILE_FORMAT_PLAIN: - case CAS_PGT_STORAGE_FILE_FORMAT_XML: - $this->_format = $format; - break; - default: - phpCAS::error('unknown PGT file storage format (`'.CAS_PGT_STORAGE_FILE_FORMAT_PLAIN.'\' and `'.CAS_PGT_STORAGE_FILE_FORMAT_XML.'\' allowed)'); - } phpCAS::traceEnd(); } @@ -154,14 +150,16 @@ class PGTStorageFile extends PGTStorage /** * 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; + if ($this->isInitialized()) { + return; + } // call the ancestor's method (mark as initialized) parent::init(); phpCAS::traceEnd(); @@ -174,7 +172,7 @@ class PGTStorageFile extends PGTStorage /** * This method returns the filename corresponding to a PGT Iou. * - * @param $pgt_iou the PGT iou. + * @param string $pgt_iou the PGT iou. * * @return a filename * @private @@ -182,7 +180,7 @@ class PGTStorageFile extends PGTStorage function getPGTIouFilename($pgt_iou) { phpCAS::traceBegin(); - $filename = $this->getPath().$pgt_iou.'.'.$this->getFormat(); + $filename = $this->getPath().$pgt_iou.'.plain'; phpCAS::traceEnd($filename); return $filename; } @@ -191,8 +189,10 @@ class PGTStorageFile extends PGTStorage * This method stores a PGT and its corresponding PGT Iou into a file. Echoes a * warning on error. * - * @param $pgt the PGT - * @param $pgt_iou the PGT iou + * @param string $pgt the PGT + * @param string $pgt_iou the PGT iou + * + * @return void * * @public */ @@ -200,13 +200,21 @@ class PGTStorageFile extends PGTStorage { phpCAS::traceBegin(); $fname = $this->getPGTIouFilename($pgt_iou); - if ( $f=fopen($fname,"w") ) { - if ( fputs($f,$pgt) === FALSE ) { - phpCAS::error('could not write PGT to `'.$fname.'\''); + 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.'\''); } - fclose($f); } else { - phpCAS::error('could not open `'.$fname.'\''); + phpCAS::error('File exists: `'.$fname.'\''); } phpCAS::traceEnd(); } @@ -215,7 +223,7 @@ class PGTStorageFile extends PGTStorage * This method reads a PGT corresponding to a PGT Iou and deletes the * corresponding file. * - * @param $pgt_iou the PGT iou + * @param string $pgt_iou the PGT iou * * @return the corresponding PGT, or FALSE on error * @@ -224,20 +232,23 @@ class PGTStorageFile extends PGTStorage function read($pgt_iou) { phpCAS::traceBegin(); - $pgt = FALSE; + $pgt = false; $fname = $this->getPGTIouFilename($pgt_iou); - if ( !($f=fopen($fname,"r")) ) { - phpCAS::trace('could not open `'.$fname.'\''); - } else { - if ( ($pgt=fgets($f)) === FALSE ) { - phpCAS::trace('could not read PGT from `'.$fname.'\''); + 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); } - fclose($f); + // delete the PGT file + @unlink($fname); + } else { + phpCAS::error('No such file `'.$fname.'\''); } - - // delete the PGT file - @unlink($fname); - phpCAS::traceEnd($pgt); return $pgt; } @@ -245,6 +256,4 @@ class PGTStorageFile extends PGTStorage /** @} */ } - - ?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-db.php b/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-db.php deleted file mode 100644 index 57018c31..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/PGTStorage/pgt-db.php +++ /dev/null @@ -1,191 +0,0 @@ - - * - * @ingroup internalPGTStorageDB - */ - -class PGTStorageDB extends PGTStorage -{ - /** - * @addtogroup internalPGTStorageDB - * @{ - */ - - /** - * a string representing a PEAR DB URL to connect to the database. Written by - * PGTStorageDB::PGTStorageDB(), read by getURL(). - * - * @hideinitializer - * @private - */ - var $_url=''; - - /** - * This method returns the PEAR DB URL to use to connect to the database. - * - * @return a PEAR DB URL - * - * @private - */ - function getURL() - { - return $this->_url; - } - - /** - * The handle of the connection to the database where PGT's are stored. Written by - * PGTStorageDB::init(), read by getLink(). - * - * @hideinitializer - * @private - */ - var $_link = null; - - /** - * This method returns the handle of the connection to the database where PGT's are - * stored. - * - * @return a handle of connection. - * - * @private - */ - function getLink() - { - return $this->_link; - } - - /** - * The name of the table where PGT's are stored. Written by - * PGTStorageDB::PGTStorageDB(), read by getTable(). - * - * @hideinitializer - * @private - */ - var $_table = ''; - - /** - * This method returns the name of the table where PGT's are stored. - * - * @return the name of a 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 "database"; - } - - /** - * This method returns an informational string giving informations on the - * parameters of the storage.(used for debugging purposes). - * - * @public - */ - function getStorageInfo() - { - return 'url=`'.$this->getURL().'\', table=`'.$this->getTable().'\''; - } - - // ######################################################################## - // CONSTRUCTOR - // ######################################################################## - - /** - * The class constructor, called by CASClient::SetPGTStorageDB(). - * - * @param $cas_parent the CASClient instance that creates the object. - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function PGTStorageDB($cas_parent,$user,$password,$database_type,$hostname,$port,$database,$table) - { - phpCAS::traceBegin(); - - // call the ancestor's constructor - $this->PGTStorage($cas_parent); - - if ( empty($database_type) ) $database_type = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE_TYPE; - if ( empty($hostname) ) $hostname = CAS_PGT_STORAGE_DB_DEFAULT_HOSTNAME; - if ( $port==0 ) $port = CAS_PGT_STORAGE_DB_DEFAULT_PORT; - if ( empty($database) ) $database = CAS_PGT_STORAGE_DB_DEFAULT_DATABASE; - if ( empty($table) ) $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; - - // build and store the PEAR DB URL - $this->_url = $database_type.':'.'//'.$user.':'.$password.'@'.$hostname.':'.$port.'/'.$database; - - // XXX should use setURL and setTable - phpCAS::traceEnd(); - } - - // ######################################################################## - // INITIALIZATION - // ######################################################################## - - /** - * This method is used to initialize the storage. Halts on error. - * - * @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(); - - //include phpDB library (the test was introduced in release 0.4.8 for - //the integration into Tikiwiki). - if (!class_exists('DB')) { - include_once('DB.php'); - } - - // try to connect to the database - $this->_link = DB::connect($this->getURL()); - if ( DB::isError($this->_link) ) { - phpCAS::error('could not connect to database ('.DB::errorMessage($this->_link).')'); - } - var_dump($this->_link); - phpCAS::traceBEnd(); - } - - /** @} */ -} - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService.php new file mode 100644 index 00000000..d70ca9c1 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService.php @@ -0,0 +1,72 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Abstract.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Abstract.php new file mode 100644 index 00000000..fade9e70 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Abstract.php @@ -0,0 +1,149 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Exception.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Exception.php new file mode 100644 index 00000000..5a1e6962 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Exception.php @@ -0,0 +1,46 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http.php new file mode 100644 index 00000000..7c9824fa --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http.php @@ -0,0 +1,91 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Abstract.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Abstract.php new file mode 100644 index 00000000..abeddf8b --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Abstract.php @@ -0,0 +1,360 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Get.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Get.php new file mode 100644 index 00000000..78e35de1 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Get.php @@ -0,0 +1,85 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Post.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Post.php new file mode 100644 index 00000000..7d4ecd3c --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Http/Post.php @@ -0,0 +1,152 @@ + + * @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('example.search'); + * $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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Imap.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Imap.php new file mode 100644 index 00000000..847da28c --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Imap.php @@ -0,0 +1,280 @@ + + * @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 + * @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: '.$this->_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/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Testable.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Testable.php new file mode 100644 index 00000000..51f07676 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxiedService/Testable.php @@ -0,0 +1,75 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain.php new file mode 100644 index 00000000..2594d141 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain.php @@ -0,0 +1,127 @@ + + * @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 + * @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) + { + // Ensure that we have an indexed array + $this->chain = array_values($chain); + } + + /** + * 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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/AllowedList.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/AllowedList.php new file mode 100644 index 00000000..62d196ab --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/AllowedList.php @@ -0,0 +1,119 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Any.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Any.php new file mode 100644 index 00000000..0cd92f74 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Any.php @@ -0,0 +1,64 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Interface.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Interface.php new file mode 100644 index 00000000..d247115d --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Interface.php @@ -0,0 +1,53 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Trusted.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Trusted.php new file mode 100644 index 00000000..7fa61296 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyChain/Trusted.php @@ -0,0 +1,59 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/ProxyTicketException.php b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyTicketException.php new file mode 100644 index 00000000..72330466 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/ProxyTicketException.php @@ -0,0 +1,71 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Request/AbstractRequest.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/AbstractRequest.php new file mode 100644 index 00000000..f3dd28b7 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/AbstractRequest.php @@ -0,0 +1,379 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlMultiRequest.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlMultiRequest.php new file mode 100644 index 00000000..410aba0e --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlMultiRequest.php @@ -0,0 +1,146 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlRequest.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlRequest.php new file mode 100644 index 00000000..dd866dc8 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/CurlRequest.php @@ -0,0 +1,200 @@ + + * @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 + * @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, 0); + } + 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); + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 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/include/limesurvey/admin/classes/phpCAS/CAS/Request/Exception.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/Exception.php new file mode 100644 index 00000000..14ff3c6b --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/Exception.php @@ -0,0 +1,45 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Request/MultiRequestInterface.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/MultiRequestInterface.php new file mode 100644 index 00000000..abc44868 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/MultiRequestInterface.php @@ -0,0 +1,83 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/Request/RequestInterface.php b/include/limesurvey/admin/classes/phpCAS/CAS/Request/RequestInterface.php new file mode 100644 index 00000000..cc11ba43 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/Request/RequestInterface.php @@ -0,0 +1,179 @@ + + * @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 + * @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/include/limesurvey/admin/classes/phpCAS/CAS/TypeMismatchException.php b/include/limesurvey/admin/classes/phpCAS/CAS/TypeMismatchException.php new file mode 100644 index 00000000..4a13c2df --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/CAS/TypeMismatchException.php @@ -0,0 +1,70 @@ + + * @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 + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ +class CAS_TypeMismatchException +extends CAS_InvalidArgumentException +{ + /** + * Constructor, provides a nice message. + * + * @param mixed $argument Argument + * @param string $argumentName Argument Name + * @param string $type Type + * @param string $message Error Message + * @param integer $code Code + * + * @return void + */ + public function __construct ( + $argument, $argumentName, $type, $message = '', $code = 0 + ) { + if (is_object($argument)) { + $foundType = get_class($argument).' object'; + } else { + $foundType = gettype($argument); + } + + parent::__construct( + 'type mismatched for parameter ' + . $argumentName . ' (should be \'' . $type .' \'), ' + . $foundType . ' given. ' . $message, $code + ); + } +} +?> diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/client.php b/include/limesurvey/admin/classes/phpCAS/CAS/client.php deleted file mode 100644 index c218c524..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/client.php +++ /dev/null @@ -1,2297 +0,0 @@ - - */ - -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) - ? '__TITLE__

__TITLE__

' - : $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) - ?('
phpCAS __PHPCAS_VERSION__ '.$this->getString(CAS_STR_USING_SERVER).' __SERVER_BASE_URL__ (CAS __CAS_VERSION__)
') - :$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() - .':' - .$this->getServerPort() - .$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 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 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(); - - if (!$this->isLogoutRequest() && !empty($_GET['ticket']) && $start_session) { - // copy old session vars and destroy the current session - if (!isset($_SESSION)) { - session_start(); - } - $old_session = $_SESSION; - session_destroy(); - // set up a new session, of name based on the ticket - $session_id = preg_replace('/[^\w]/','',$_GET['ticket']); - phpCAS::LOG("Session ID: " . $session_id); - session_id($session_id); - if (!isset($_SESSION)) { - session_start(); - } - // restore old session vars - $_SESSION = $old_session; - // Redirect to location without ticket. - header('Location: '.$this->getURL()); - } - - //activate session mechanism if desired - if (!$this->isLogoutRequest() && $start_session) { - session_start(); - } - - $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; - 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; - } - } - 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; - } - - /** - * 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. - * - * @public - */ - function isAuthenticated() - { - phpCAS::traceBegin(); - $res = FALSE; - $validate_url = ''; - - if ( $this->wasPreviouslyAuthenticated() ) { - // 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; - } - elseif ( $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; - } - else { - // no ticket given, not authenticated - phpCAS::trace('no ticket found'); - } - - 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']); - 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('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$cas_url); - $this->printHTMLFooter(); - phpCAS::traceExit(); - exit(); - } - - // /** - // * This method is used to logout from CAS. - // * @param $url a URL that will be transmitted to the CAS server (to come back to when logged out) - // * @public - // */ - // function logout($url = "") { - // phpCAS::traceBegin(); - // $cas_url = $this->getServerLogoutURL(); - // // v0.4.14 sebastien.gougeon at univ-rennes1.fr - // // header('Location: '.$cas_url); - // if ( $url != "" ) { - // // Adam Moore 1.0.0RC2 - // $url = '?service=' . $url . '&url=' . $url; - // } - // header('Location: '.$cas_url . $url); - // session_unset(); - // session_destroy(); - // $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT)); - // printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$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); - session_unset(); - session_destroy(); - $this->printHTMLHeader($this->getString(CAS_STR_LOGOUT)); - printf('

'.$this->getString(CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED).'

',$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; - } - 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); - $allowed = false; - foreach ($allowed_clients as $allowed_client) { - if ($client == $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("|(.*)|", $_POST['logoutRequest'], $tick, PREG_OFFSET_CAPTURE, 3); - $wrappedSamlSessionIndex = preg_replace('||','',$tick[0][0]); - $ticket2logout = preg_replace('||','',$wrappedSamlSessionIndex); - phpCAS::log("Ticket to logout: ".$ticket2logout); - $session_id = preg_replace('/[^\w]/','',$ticket2logout); - phpCAS::log("Session id: ".$session_id); - - // fix New 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. - * - * @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='.$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(' found, but no '); - $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(' 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 nor found'); - $this->authError('ST not validated', - $validate_url, - FALSE/*$no_response*/, - TRUE/*$bad_response*/, - $text_response); - } - break; - } - - // at this step, ST has been validated and $this->_user has been set, - phpCAS::traceEnd(TRUE); - return TRUE; - } - - /** @} */ - - // 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(); - $this->printHTMLHeader('phpCAS callback'); - $pgt_iou = $_GET['pgtIou']; - $pgt = $_GET['pgtId']; - phpCAS::trace('Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\')'); - echo '

Storing PGT `'.$pgt.'\' (id=`'.$pgt_iou.'\').

'; - $this->storePGT($pgt,$pgt_iou); - $this->printHTMLFooter(); - phpCAS::traceExit(); - } - - /** @} */ - - // ######################################################################## - // 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); - } - - /** - * This method is used to tell phpCAS to store the response of the - * CAS server to PGT requests into a database. - * @note The connection to the database is done only when needed. - * As a consequence, bad parameters are detected only when - * initializing PGT storage. - * - * @param $user the user to access the data with - * @param $password the user's password - * @param $database_type the type of the database hosting the data - * @param $hostname the server hosting the database - * @param $port the port the server is listening on - * @param $database the name of the database - * @param $table the name of the table storing the data - * - * @public - */ - function setPGTStorageDB($user, - $password, - $database_type, - $hostname, - $port, - $database, - $table) - { - // check that the storage has not already been set - if ( is_object($this->_pgt_storage) ) { - phpCAS::error('PGT storage already defined'); - } - - // warn the user that he should use file storage... - trigger_error('PGT storage into database is an experimental feature, use at your own risk',E_USER_WARNING); - - // create the storage object - $this->_pgt_storage = new PGTStorageDB($this,$user,$password,$database_type,$hostname,$port,$database,$table); - } - - // ######################################################################## - // 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) - { - phpCAS::traceBegin(); - if ( sizeof($arr = $tree_response->get_elements_by_tagname("proxyGrantingTicket")) == 0) { - phpCAS::trace(' 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()); - $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); - } - phpCAS::traceEnd(TRUE); - 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(' was found, but not '); - } - } - // 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 nor 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 != '' ) { - 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)); - } - // perform the query - $buf = curl_exec ($ch); - if ( $buf === FALSE ) { - phpCAS::trace('curl_exec() failed'); - $err_msg = 'CURL error #'.curl_errno($ch).': '.curl_error($ch); - // 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 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 - if ( is_array($_SESSION['phpCAS']['services'][$url]['cookies']) ) { - foreach ( $_SESSION['phpCAS']['services'][$url]['cookies'] as $name => $val ) { - $cookies[] = $name.'='.$val; - } - } - - // 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:'); - 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($res); - return $res; - } - - /** - * 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 $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,$flags,&$err_code,&$err_msg,&$pt) - { - phpCAS::traceBegin(); - // at first retrieve a PT - $pt = $this->retrievePT($target_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); } - - /** @} */ - // ######################################################################## - // PT VALIDATION - // ######################################################################## - /** - * @addtogroup internalProxied - * @{ - */ - - /** - * This method is used to validate a PT; halt on failure - * - * @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='.$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); - } - - // 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']; - } - } - - $final_uri .= strtok($_SERVER['REQUEST_URI'],"?"); - $cgi_params = '?'.strtok("?"); - // remove the ticket if present in the CGI parameters - $cgi_params = preg_replace('/&ticket=[^&]*/','',$cgi_params); - $cgi_params = preg_replace('/\?ticket=[^&;]*/','?',$cgi_params); - $cgi_params = preg_replace('/\?%26/','?',$cgi_params); - $cgi_params = preg_replace('/\?&/','?',$cgi_params); - $cgi_params = preg_replace('/\?$/','',$cgi_params); - $final_uri .= $cgi_params; - $this->setURL($final_uri); - } - phpCAS::traceEnd($this->_url); - return $this->_url; - } - - /** - * 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),$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(); - } - - /** @} */ -} - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/domxml-php4-php5.php b/include/limesurvey/admin/classes/phpCAS/CAS/domxml-php4-php5.php deleted file mode 100644 index b21013a0..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/domxml-php4-php5.php +++ /dev/null @@ -1,277 +0,0 @@ - - * { - * if (version_compare(PHP_VERSION,'5','>=')) - * require_once('domxml-php4-to-php5.php'); - * } - * - * - * Version 1.5.5, 2005-01-18, http://alexandre.alapetite.net/doc-alex/domxml-php4-php5/ - * - * ------------------------------------------------------------------
- * Written by Alexandre Alapetite, http://alexandre.alapetite.net/cv/ - * - * Copyright 2004, Licence: Creative Commons "Attribution-ShareAlike 2.0 France" BY-SA (FR), - * http://creativecommons.org/licenses/by-sa/2.0/fr/ - * http://alexandre.alapetite.net/divers/apropos/#by-sa - * - Attribution. You must give the original author credit - * - Share Alike. If you alter, transform, or build upon this work, - * you may distribute the resulting work only under a license identical to this one - * - The French law is authoritative - * - Any of these conditions can be waived if you get permission from Alexandre Alapetite - * - 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.net/doc-alex/domxml-php4-php5/ - */ - -function domxml_new_doc($version) {return new php4DOMDocument('');} -function domxml_open_file($filename) {return new php4DOMDocument($filename);} -function domxml_open_mem($str) -{ - $dom=new php4DOMDocument(''); - $dom->myDOMNode->loadXML($str); - return $dom; -} -function xpath_eval($xpath_context,$eval_str,$contextnode=null) {return $xpath_context->query($eval_str,$contextnode);} -function xpath_new_context($dom_document) {return new php4DOMXPath($dom_document);} - -class php4DOMAttr extends php4DOMNode -{ - function php4DOMAttr($aDOMAttr) {$this->myDOMNode=$aDOMAttr;} - function Name() {return $this->myDOMNode->name;} - function Specified() {return $this->myDOMNode->specified;} - function Value() {return $this->myDOMNode->value;} -} - -class php4DOMDocument extends php4DOMNode -{ - function php4DOMDocument($filename='') - { - $this->myDOMNode=new DOMDocument(); - if ($filename!='') $this->myDOMNode->load($filename); - } - function create_attribute($name,$value) - { - $myAttr=$this->myDOMNode->createAttribute($name); - $myAttr->value=$value; - 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_text_node($content) {return new php4DOMNode($this->myDOMNode->createTextNode($content),$this);} - function document_element() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} - function dump_file($filename,$compressionmode=false,$format=false) {return $this->myDOMNode->save($filename);} - function dump_mem($format=false,$encoding=false) {return $this->myDOMNode->saveXML();} - function get_element_by_id($id) {return new php4DOMElement($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); - $i++; - } - return $nodeSet; - } - function html_dump_mem() {return $this->myDOMNode->saveHTML();} - function root() {return new php4DOMElement($this->myDOMNode->documentElement,$this);} -} - -class php4DOMElement extends php4DOMNode -{ - function get_attribute($name) {return $this->myDOMNode->getAttribute($name);} - 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); - $i++; - } - 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);} - function tagname() {return $this->myDOMNode->tagName;} -} - -class php4DOMNode -{ - var $myDOMNode; - var $myOwnerDocument; - function php4DOMNode($aDomNode,$aOwnerDocument) - { - $this->myDOMNode=$aDomNode; - $this->myOwnerDocument=$aOwnerDocument; - } - function __get($name) - { - if ($name=='type') return $this->myDOMNode->nodeType; - elseif ($name=='tagname') return $this->myDOMNode->tagName; - elseif ($name=='content') return $this->myDOMNode->textContent; - else - { - $myErrors=debug_backtrace(); - trigger_error('Undefined property: '.get_class($this).'::$'.$name.' ['.$myErrors[0]['file'].':'.$myErrors[0]['line'].']',E_USER_NOTICE); - return false; - } - } - function append_child($newnode) {return new php4DOMElement($this->myDOMNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} - function append_sibling($newnode) {return new php4DOMElement($this->myDOMNode->parentNode->appendChild($newnode->myDOMNode),$this->myOwnerDocument);} - function attributes() - { - $myDOMNodeList=$this->myDOMNode->attributes; - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMAttr($node,$this->myOwnerDocument); - $i++; - } - return $nodeSet; - } - function child_nodes() - { - $myDOMNodeList=$this->myDOMNode->childNodes; - $nodeSet=array(); - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - $nodeSet[]=new php4DOMElement($node,$this->myOwnerDocument); - $i++; - } - return $nodeSet; - } - function children() {return $this->child_nodes();} - function clone_node($deep=false) {return new php4DOMElement($this->myDOMNode->cloneNode($deep),$this->myOwnerDocument);} - function first_child() {return new php4DOMElement($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 new php4DOMElement($this->myDOMNode->insertBefore($newnode->myDOMNode,$refnode->myDOMNode),$this->myOwnerDocument);} - function is_blank_node() - { - $myDOMNodeList=$this->myDOMNode->childNodes; - $i=0; - if (isset($myDOMNodeList)) - while ($node=$myDOMNodeList->item($i)) - { - if (($node->nodeType==XML_ELEMENT_NODE)|| - (($node->nodeType==XML_TEXT_NODE)&&!preg_match('/^([[:cntrl:]]|[[:space:]])*$/',$node->nodeValue))) - return false; - $i++; - } - return true; - } - function last_child() {return new php4DOMElement($this->myDOMNode->lastChild,$this->myOwnerDocument);} - function new_child($name,$content) - { - $mySubNode=$this->myDOMNode->ownerDocument->createElement($name); - $mySubNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($content)); - $this->myDOMNode->appendChild($mySubNode); - return new php4DOMElement($mySubNode,$this->myOwnerDocument); - } - function next_sibling() {return new php4DOMElement($this->myDOMNode->nextSibling,$this->myOwnerDocument);} - function node_name() {return $this->myDOMNode->localName;} - function node_type() {return $this->myDOMNode->nodeType;} - function node_value() {return $this->myDOMNode->nodeValue;} - function owner_document() {return $this->myOwnerDocument;} - function parent_node() {return new php4DOMElement($this->myDOMNode->parentNode,$this->myOwnerDocument);} - function prefix() {return $this->myDOMNode->prefix;} - function previous_sibling() {return new php4DOMElement($this->myDOMNode->previousSibling,$this->myOwnerDocument);} - function remove_child($oldchild) {return new php4DOMElement($this->myDOMNode->removeChild($oldchild->myDOMNode),$this->myOwnerDocument);} - function replace_child($oldnode,$newnode) {return new php4DOMElement($this->myDOMNode->replaceChild($oldnode->myDOMNode,$newnode->myDOMNode),$this->myOwnerDocument);} - function set_content($text) - { - if (($this->myDOMNode->hasChildNodes())&&($this->myDOMNode->firstChild->nodeType==XML_TEXT_NODE)) - $this->myDOMNode->removeChild($this->myDOMNode->firstChild); - return $this->myDOMNode->appendChild($this->myDOMNode->ownerDocument->createTextNode($text)); - } -} - -class php4DOMNodelist -{ - var $myDOMNodelist; - var $nodeset; - function php4DOMNodelist($aDOMNodelist,$aOwnerDocument) - { - $this->myDOMNodelist=$aDOMNodelist; - $this->nodeset=array(); - $i=0; - if (isset($this->myDOMNodelist)) - while ($node=$this->myDOMNodelist->item($i)) - { - $this->nodeset[]=new php4DOMElement($node,$aOwnerDocument); - $i++; - } - } -} - -class php4DOMXPath -{ - var $myDOMXPath; - var $myOwnerDocument; - function php4DOMXPath($dom_document) - { - $this->myOwnerDocument=$dom_document; - $this->myDOMXPath=new DOMXPath($dom_document->myDOMNode); - } - function query($eval_str,$contextnode) - { - if (isset($contextnode)) return new php4DOMNodelist($this->myDOMXPath->query($eval_str,$contextnode->myDOMNode),$this->myOwnerDocument); - else return new php4DOMNodelist($this->myDOMXPath->query($eval_str),$this->myOwnerDocument); - } - function xpath_register_ns($prefix,$namespaceURI) {return $this->myDOMXPath->registerNamespace($prefix,$namespaceURI);} -} - -if (extension_loaded('xsl')) -{//See also: http://alexandre.alapetite.net/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 -{ - var $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();} -} -} -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/catalan.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/catalan.php deleted file mode 100644 index 5c6a4d84..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/catalan.php +++ /dev/null @@ -1,28 +0,0 @@ -_strings = array( -CAS_STR_USING_SERVER -=> 'usant servidor', -CAS_STR_AUTHENTICATION_WANTED -=> 'Autentificació CAS necessària!', -CAS_STR_LOGOUT -=> 'Sortida de CAS necessària!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'Ja hauria d\ haver estat redireccionat al servidor CAS. Feu click aquí per a continuar.', -CAS_STR_AUTHENTICATION_FAILED -=> 'Autentificació CAS fallida!', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

No estàs autentificat.

Pots tornar a intentar-ho fent click aquí.

Si el problema persisteix hauría de contactar amb l\'administrador d\'aquest llocc.

', -CAS_STR_SERVICE_UNAVAILABLE -=> 'El servei `%s\' no està disponible (%s).' -); - -?> diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/english.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/english.php deleted file mode 100644 index d8836c6f..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/english.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( -CAS_STR_USING_SERVER -=> 'using server', -CAS_STR_AUTHENTICATION_WANTED -=> 'CAS Authentication wanted!', -CAS_STR_LOGOUT -=> 'CAS logout wanted!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'You should already have been redirected to the CAS server. Click here to continue.', -CAS_STR_AUTHENTICATION_FAILED -=> 'CAS Authentication failed!', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

You were not authenticated.

You may submit your request again by clicking here.

If the problem persists, you may contact the administrator of this site.

', -CAS_STR_SERVICE_UNAVAILABLE -=> 'The service `%s\' is not available (%s).' -); - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/french.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/french.php deleted file mode 100644 index 843bdccb..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/french.php +++ /dev/null @@ -1,29 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( -CAS_STR_USING_SERVER -=> 'utilisant le serveur', -CAS_STR_AUTHENTICATION_WANTED -=> 'Authentication CAS n�cessaire !', -CAS_STR_LOGOUT -=> 'D�connexion demand�e !', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'Vous auriez du etre redirig�(e) vers le serveur CAS. Cliquez ici pour continuer.', -CAS_STR_AUTHENTICATION_FAILED -=> 'Authentification CAS infructueuse !', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

Vous n\'avez pas �t� authentifi�(e).

Vous pouvez soumettre votre requete � nouveau en cliquant ici.

Si le probl�me persiste, vous pouvez contacter l\'administrateur de ce site.

', -CAS_STR_SERVICE_UNAVAILABLE -=> 'Le service `%s\' est indisponible (%s)' - -); - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/german.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/german.php deleted file mode 100644 index bc6fa8fd..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/german.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( -CAS_STR_USING_SERVER -=> 'via Server', -CAS_STR_AUTHENTICATION_WANTED -=> 'CAS Authentifizierung erforderlich!', -CAS_STR_LOGOUT -=> 'CAS Abmeldung!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'eigentlich häten Sie zum CAS Server weitergeleitet werden sollen. Drücken Sie hier um fortzufahren.', -CAS_STR_AUTHENTICATION_FAILED -=> 'CAS Anmeldung fehlgeschlagen!', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

Sie wurden nicht angemeldet.

Um es erneut zu versuchen klicken Sie hier.

Wenn das Problem bestehen bleibt, kontkatieren Sie den Administrator dieser Seite.

', -CAS_STR_SERVICE_UNAVAILABLE -=> 'Der Dienst `%s\' ist nicht verfügbar (%s).' -); - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/greek.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/greek.php deleted file mode 100644 index 9da1bd03..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/greek.php +++ /dev/null @@ -1,28 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -$this->_strings = array( -CAS_STR_USING_SERVER -=> '��������������� � ������������', -CAS_STR_AUTHENTICATION_WANTED -=> '���������� � ����������� CAS!', -CAS_STR_LOGOUT -=> '���������� � ���������� ��� CAS!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> '�� ������ �� ������ �������������� ���� ����������� CAS. ����� ���� ��� ��� �� ����������.', -CAS_STR_AUTHENTICATION_FAILED -=> '� ����������� CAS �������!', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

��� ���������������.

�������� �� ����������������, �������� ���� ���.

��� �� �������� ���������, ����� �� ����� �� ��� �����������.

', -CAS_STR_SERVICE_UNAVAILABLE -=> '� �������� `%s\' ��� ����� ��������� (%s).' -); - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/japanese.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/japanese.php deleted file mode 100644 index 09ee11ce..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/japanese.php +++ /dev/null @@ -1,28 +0,0 @@ -_strings = array( -CAS_STR_USING_SERVER -=> 'using server', -CAS_STR_AUTHENTICATION_WANTED -=> 'CAS�ˤ��ǧ�ڤ�Ԥ��ޤ�', -CAS_STR_LOGOUT -=> 'CAS����?�����Ȥ��ޤ�!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'CAS�����Ф˹Ԥ�ɬ�פ�����ޤ�����ưŪ��ž������ʤ����� ������ �򥯥�å�����³�Ԥ��ޤ���', -CAS_STR_AUTHENTICATION_FAILED -=> 'CAS�ˤ��ǧ�ڤ˼��Ԥ��ޤ���', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

ǧ�ڤǤ��ޤ���Ǥ���.

�⤦���٥ꥯ�����Ȥ�������������������򥯥�å�.

���꤬��褷�ʤ����� ���Υ����Ȥδ�������䤤��碌�Ƥ�������.

', -CAS_STR_SERVICE_UNAVAILABLE -=> '�����ӥ� `%s\' �����ѤǤ��ޤ��� (%s).' -); - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/languages.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/languages.php deleted file mode 100644 index 001cfe44..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/languages.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @sa @link internalLang Internationalization @endlink - * @ingroup internalLang - */ - -//@{ -/** - * a phpCAS string index - */ -define("CAS_STR_USING_SERVER", 1); -define("CAS_STR_AUTHENTICATION_WANTED", 2); -define("CAS_STR_LOGOUT", 3); -define("CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED", 4); -define("CAS_STR_AUTHENTICATION_FAILED", 5); -define("CAS_STR_YOU_WERE_NOT_AUTHENTICATED", 6); -define("CAS_STR_SERVICE_UNAVAILABLE", 7); -//@} - -?> \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/CAS/languages/spanish.php b/include/limesurvey/admin/classes/phpCAS/CAS/languages/spanish.php deleted file mode 100644 index 42ebba56..00000000 --- a/include/limesurvey/admin/classes/phpCAS/CAS/languages/spanish.php +++ /dev/null @@ -1,28 +0,0 @@ -_strings = array( -CAS_STR_USING_SERVER -=> 'usando servidor', -CAS_STR_AUTHENTICATION_WANTED -=> '¡Autentificación CAS necesaria!', -CAS_STR_LOGOUT -=> '¡Salida CAS necesaria!', -CAS_STR_SHOULD_HAVE_BEEN_REDIRECTED -=> 'Ya debería haber sido redireccionado al servidor CAS. Haga click aquí para continuar.', -CAS_STR_AUTHENTICATION_FAILED -=> '¡Autentificación CAS fallida!', -CAS_STR_YOU_WERE_NOT_AUTHENTICATED -=> '

No estás autentificado.

Puedes volver a intentarlo haciendo click aquí.

Si el problema persiste debería contactar con el administrador de este sitio.

', -CAS_STR_SERVICE_UNAVAILABLE -=> 'El servicio `%s\' no está disponible (%s).' -); - -?> diff --git a/include/limesurvey/admin/classes/phpCAS/LICENSE b/include/limesurvey/admin/classes/phpCAS/LICENSE new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/LICENSE @@ -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/include/limesurvey/admin/classes/phpCAS/NOTICE b/include/limesurvey/admin/classes/phpCAS/NOTICE new file mode 100644 index 00000000..70d9ffcd --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/NOTICE @@ -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/include/limesurvey/admin/classes/phpCAS/README b/include/limesurvey/admin/classes/phpCAS/README deleted file mode 100644 index 9b38b2ad..00000000 --- a/include/limesurvey/admin/classes/phpCAS/README +++ /dev/null @@ -1,36 +0,0 @@ -README -phpCAS - http://www.ja-sig.org/wiki/display/CASC/phpCAS -This software contains a client library for PHP, which can be used to identify -Central Authentication Service (CAS) authenticated users. - -Please see the phpCAS website for more information. - -http://www.ja-sig.org/wiki/display/CASC/phpCAS - -LICENSE -Copyright © 2003-2008, 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. diff --git a/include/limesurvey/admin/classes/phpCAS/README.md b/include/limesurvey/admin/classes/phpCAS/README.md new file mode 100644 index 00000000..583c1dce --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/README.md @@ -0,0 +1,31 @@ +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 + +[![Build Status](https://travis-ci.org/Jasig/phpCAS.png)](https://travis-ci.org/Jasig/phpCAS) + + +LICENSE +------- + +Copyright 2007-2015, 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/include/limesurvey/admin/classes/phpCAS/docs/Building b/include/limesurvey/admin/classes/phpCAS/docs/Building new file mode 100644 index 00000000..1b4a5c32 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/Building @@ -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/include/limesurvey/admin/classes/phpCAS/docs/ChangeLog b/include/limesurvey/admin/classes/phpCAS/docs/ChangeLog new file mode 100644 index 00000000..d8a43224 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/ChangeLog @@ -0,0 +1,565 @@ +Changes in version 1.3.4 +Security Fixes: + +Bug Fixes: + * Mark auth call completed for post-auth callback [#131] (Daniel Frett) + * Remove typo CAS_TypeMismatchException [#133] (Gabrijel Gavranović) + * Fix SERVER_ADMIN error for alternate Webservers [#103] (Joachim Fritschi) + * Fix non-strict string comparision in _isHttps check [#139] (Brandon Peters) + * Fix setNoCasServerValidation for cURL 7.10 [#122] (Joachim Fritschi) + * Fix renew support [#93] (Joachim Fritschi) + * _getClientUrl() fixes with reverse proxies [#154] adongy + * Param type doc should be 'string' in CAS::logoutWithRedirectService() [#167] Chris McCafferty + * Fix broken class reference [#161] Joachim Fritschi + + +Improvement: + * Add phpCAS::isInitialized() API method [#112] (Adam Franco) + * select temporary directory based on env vars [#136) (Geoffroy Desvernay) + * Add gitattributes to reduce unnecessary files from composer installs. [#141] (Jon Dufresne) + * Allow cas endpoint to be a 'get url' [#146] (flushbi) + * Add documentation for phpCAS::$_PHPCAS_CLIENT [#156] (Sylvain) + * Improve https check [#139] (Joachim Fritschi) + * Add time to trace [#158] (cwsterling) + * Add php5.6 tests, move to faster docker env [#169] (Florian Holzhauer) + * Introduce a setVerbose() toggle to prevent debug info leaking in production [#152 #147] (Joachim Fritschi) + + +Changes in version 1.3.3 +Security Fixes: + * CVE-2014-4172 Urlencode all tickets [#125] (Marvin Addison) + +Bug Fixes: + * Fix CURL compatibility CURL >= 7.28.0 [#66] (adoy) + * Commit session before redirect [#79] (kakawait) + * Fix warnings for php => 5.5 [87] (fh) + * Update wrong wording in examples [#90] (misilot) + * Fixed bug in imap.php [#105] (echampet) + * Fix missing Server_Admin variable for nginex [#121](arianf) + * Fix error in TypeMismatchException [#123 ](Develle) + * Fix bug in https test [#126] (Florent Baldino) + + +Improvement: + * Fix grammar of documentation [#61] (frett) + * Improved testability of the phpCAS client [#7] (Adam Franco) + * Fixed typo [#70] (fh) + * Example for improved cookie hardening [#67] (Joachim Fritschi) + * Added support for X-Forwarded-Proto Header [#77] (Paul Donohue) + * Added composer support [#73] (dhyde) + * Travis for continuous integration [#82] (fh) + * Support for X-Forwared-Port [#100] (neopeak) + * Support for CAS 3.0 protocol [#116] (fredrik-w) + + +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/include/limesurvey/admin/classes/phpCAS/docs/Upgrading b/include/limesurvey/admin/classes/phpCAS/docs/Upgrading new file mode 100644 index 00000000..27df91f4 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/Upgrading @@ -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/include/limesurvey/admin/classes/phpCAS/docs/examples/config.example.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/config.example.php new file mode 100644 index 00000000..2ada01ca --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/config.example.php @@ -0,0 +1,104 @@ + + * @author Adam Franco + * @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'); + +// Client config for cookie hardening +$client_domain = '127.0.0.1'; +$client_path = 'phpcas'; +$client_secure = true; +$client_httpOnly = true; +$client_lifetime = 0; + +// 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/include/limesurvey/admin/classes/phpCAS/docs/examples/create_pgt_storage_db_table.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/create_pgt_storage_db_table.php new file mode 100644 index 00000000..5c424c6b --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/create_pgt_storage_db_table.php @@ -0,0 +1,53 @@ + + * @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(); +?> + + + phpCAS PGT db storage table creation + + + +
+' . $db_table . ' successfully created in database ' . $db . ''; +?> +
+ + \ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example.css b/include/limesurvey/admin/classes/phpCAS/docs/examples/example.css new file mode 100644 index 00000000..bf7f6c48 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example.css @@ -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/include/limesurvey/admin/classes/phpCAS/docs/examples/example_advanced_saml11.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_advanced_saml11.php new file mode 100644 index 00000000..3c495180 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_advanced_saml11.php @@ -0,0 +1,82 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +if (isset($_REQUEST['logout'])) { + phpCAS::logout(); +} +?> + + + Advanced SAML 1.1 example + + +

Advanced SAML 1.1 example

+ + +Authentication succeeded for user +. + +

User Attributes

+
    + $value) { + if (is_array($value)) { + echo '
  • ', $key, ':
      '; + foreach ($value as $item) { + echo '
    1. ', $item, '
    2. '; + } + echo '
  • '; + } else { + echo '
  • ', $key, ': ', $value, '
  • ' . PHP_EOL; + } +} + ?> +
+

Logout

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_custom_urls.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_custom_urls.php new file mode 100644 index 00000000..97c155fe --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_custom_urls.php @@ -0,0 +1,70 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +?> + + + phpCAS simple client + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+

Logout

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_gateway.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_gateway.php new file mode 100644 index 00000000..b7715c29 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_gateway.php @@ -0,0 +1,71 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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(); + +?> + + + phpCAS simple client + + + +

Successfull Authentication!

+ +

the user's login is .

+

Logout

+

Guest mode

+

Login

+

phpCAS version is .

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_hardening.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_hardening.php new file mode 100644 index 00000000..25aae275 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_hardening.php @@ -0,0 +1,85 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(false); + +// Harden session cookie to prevent some attacks on the cookie (e.g. XSS) +session_set_cookie_params($client_lifetime, $client_path, $client_domain, $client_secure, $client_httpOnly); + +// 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 +if (isset($_REQUEST['logout'])) { + phpCAS::logout(); +} +?> + + + Advanced SAML 1.1 example + + +

Advanced SAML 1.1 example

+ + +Authentication succeeded for user +. + +

User Attributes

+
    + $value) { + if (is_array($value)) { + echo '
  • ', $key, ':
      '; + foreach ($value as $item) { + echo '
    1. ', $item, '
    2. '; + } + echo '
  • '; + } else { + echo '
  • ', $key, ': ', $value, '
  • ' . PHP_EOL; + } +} + ?> +
+

Logout

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_html.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_html.php new file mode 100644 index 00000000..ec4ee9d0 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_html.php @@ -0,0 +1,76 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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( + ' + + __TITLE__ + + +

__TITLE__

' +); +phpCAS::setHTMLFooter( + '
+
+ phpCAS __PHPCAS_VERSION__, + CAS __CAS_VERSION__ (__SERVER_BASE_URL__) +
+ +' +); + +// 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 +?> + + + phpCAS simple client with HTML output customization + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_lang.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_lang.php new file mode 100644 index 00000000..1b6b3941 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_lang.php @@ -0,0 +1,63 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +?> + + + Exemple d'internationalisation de phpCAS + + +

Authentification réussie !

+ +

L'utilisateur connecté est .

+

La version de phpCAS est .

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_logout.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_logout.php new file mode 100644 index 00000000..cdf42a79 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_logout.php @@ -0,0 +1,64 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +?> + + + phpCAS simple client + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_no_ssl_cn_validation.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_no_ssl_cn_validation.php new file mode 100644 index 00000000..bf5ef004 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_no_ssl_cn_validation.php @@ -0,0 +1,68 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +?> + + + phpCAS simple client + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+

Logout

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_db.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_db.php new file mode 100644 index 00000000..b5097628 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_db.php @@ -0,0 +1,74 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + +?> + + + phpCAS proxy example with PGT storage to a database + + + +

phpCAS proxy example with PGT storage to file

+ +

the user's login is .

+

Response from service

+'; +} else { + echo '
'; +} +echo $output; +echo '
'; + ?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_file.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_file.php new file mode 100644 index 00000000..d7b420a7 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_pgt_storage_file.php @@ -0,0 +1,74 @@ + +* @author Adam Franco +* @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + +?> + + + phpCAS proxy example with PGT storage to file + + + +

phpCAS proxy example with PGT storage to file

+ +

the user's login is .

+

Response from service

+'; +} else { + echo '
'; +} + echo $output; + echo '
'; +?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_GET.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_GET.php new file mode 100644 index 00000000..665d349b --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_GET.php @@ -0,0 +1,98 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + +?> + + + phpCAS proxy example #2 + + + +

phpCAS proxied proxy example

+ +

the user's login is .

+

Response from service

+setUrl($serviceUrl); + $service->send(); + if ($service->getResponseStatusCode() == 200) { + echo '
'; + echo $service->getResponseBody(); + echo '
'; + } else { + // The service responded with an error code 404, 500, etc. + echo '
'; + echo 'The service responded with a ' + . $service->getResponseStatusCode() . ' error.'; + echo '
'; + } +} catch (CAS_ProxyTicketException $e) { + if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) { + echo '
'; + echo "Your login has timed out. You need to log in again."; + echo '
'; + } 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; +} + + ?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_POST.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_POST.php new file mode 100644 index 00000000..4e061f59 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_POST.php @@ -0,0 +1,103 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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'; + +?> + + + phpCAS proxy POST example + + + +

phpCAS proxy POST example

+ +

the user's login is .

+

Response from service

+setUrl($serviceUrl); + $service->setContentType('application/x-www-form-urlencoded'); + $service->setBody('favorite_color=blue'); + $service->send(); + if ($service->getResponseStatusCode() == 200) { + echo '
'; + echo $service->getResponseBody(); + echo '
'; + } else { + // The service responded with an error code 404, 500, etc. + echo '
'; + echo 'The service responded with a ' + . $service->getResponseStatusCode() . ' error.'; + echo $service->getResponseBody(); + echo '
'; + } +} catch (CAS_ProxyTicketException $e) { + if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE) { + echo '
'; + echo "Your login has timed out. You need to log in again."; + echo '
'; + } 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; +} + + ?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_rebroadcast.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_rebroadcast.php new file mode 100644 index 00000000..2c9bff8f --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_rebroadcast.php @@ -0,0 +1,63 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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(). + +?> + + + phpCAS proxy rebroadcast example + + + +

phpCAS proxy rebroadcast example

+

the user's login is .

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb.php new file mode 100644 index 00000000..212918fa --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb.php @@ -0,0 +1,71 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + +?> + + + phpCAS proxied proxy example (with sessioning) + + + +

phpCAS proxied proxy example (with sessioning)

+ +

the user's login is .

+

Response from service

+'; +} else { + echo '
'; +} +echo $output; +echo '
'; + ?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb_chaining.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb_chaining.php new file mode 100644 index 00000000..0ab58ebe --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_proxy_serviceWeb_chaining.php @@ -0,0 +1,71 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + +?> + + + phpCAS proxy example #2 + + + +

phpCAS proxied proxy example

+ +

the user's login is .

+

Response from service

+'; +} else { + echo '
'; +} +echo $output; +echo '
'; + ?> + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_renew.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_renew.php new file mode 100644 index 00000000..c25c2b81 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_renew.php @@ -0,0 +1,72 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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::renewAuthentication(); + +// 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(); +} + +// logout if desired +if (isset($_REQUEST['session'])) { + session_unset(); + session_destroy(); + unset($_REQUEST['session']); + header("Location: ".$_SERVER['PHP_SELF']); +} + +// for this test, simply print that the authentication was successfull +?> + + + phpCAS simple client + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+

Logout

+

Kill local Session

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service.php new file mode 100644 index 00000000..dc5aa411 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service.php @@ -0,0 +1,96 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 '

I am a service that can be proxied.

'; + +// 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 '

The user\'s login is ' . phpCAS::getUser() . '.

'; + +// increment the number of requests of the session and print it +if (!isset($_SESSION['n'])) { + $_SESSION['n'] = 0; +} +echo '

request #' . (++$_SESSION['n']) . '

'; + +?> diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_POST.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_POST.php new file mode 100644 index 00000000..74be4dfa --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_POST.php @@ -0,0 +1,105 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 + "

I only respond to POST requests. This is a " + . $_SERVER['REQUEST_METHOD'] . " request.

"; + exit; +} +if (empty($_POST['favorite_color'])) { + header('HTTP/1.1 400 Bad Request'); + print '

You must post a favorite_color.

'; + exit; +} + +print '

I am a service that responds to POST requests.

'; + +// 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 '

The user\'s login is ' . phpCAS::getUser() . '.

'; + +print + '

Your favorite color is ' . htmlentities($_POST['favorite_color']) + . '

'; + +// increment the number of requests of the session and print it +if (!isset($_SESSION['n'])) { + $_SESSION['n'] = 0; +} +echo '

request #' . (++$_SESSION['n']) . '

'; + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_that_proxies.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_that_proxies.php new file mode 100644 index 00000000..7313ebf2 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_service_that_proxies.php @@ -0,0 +1,106 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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. + + + +?> + + + phpCAS proxied proxy service example + + + +

I am a service that can be proxied. In turn, I proxy another service.

+ +

the user's login is .

+

Response from service

+'; +} else { + echo '
'; +} + echo $output; + echo '
'; +?> + + + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/example_simple.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_simple.php new file mode 100644 index 00000000..105668ac --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/example_simple.php @@ -0,0 +1,63 @@ + + * @author Adam Franco + * @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(); +// Enable verbose error messages. Disable in production! +phpCAS::setVerbose(true); + +// 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 +?> + + + phpCAS simple client + + +

Successfull Authentication!

+ +

the user's login is .

+

phpCAS version is .

+

Logout

+ + diff --git a/include/limesurvey/admin/classes/phpCAS/docs/examples/script_info.php b/include/limesurvey/admin/classes/phpCAS/docs/examples/script_info.php new file mode 100644 index 00000000..0a6c954a --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/examples/script_info.php @@ -0,0 +1,20 @@ + + * @author Adam Franco + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 + * @link https://wiki.jasig.org/display/CASC/phpCAS + */ ?> +
+
Current script
+
session_name():
+
session_id():
+
\ No newline at end of file diff --git a/include/limesurvey/admin/classes/phpCAS/docs/images/esup-portail.png b/include/limesurvey/admin/classes/phpCAS/docs/images/esup-portail.png new file mode 100644 index 0000000000000000000000000000000000000000..ed6e6661b6612ac6571e0d0eafe7991e3da75eb3 GIT binary patch literal 2621 zcmds2dpK148vZe+q>xLAw!2-aq%7N|2peS@rV=}fLR#pdX}d&8Lc8`nfg4N=*QI)_lE*7?@_bIzaVzwV! z&VXv0Vnkv@UiET>2(ddjZZ19vxl;cXd*9g2I+NpZ#>d~c-lxrG$L0`s z+g4FX`NCkme=cjNUl@FaP+jf3E?s}sUn8NX_N{+vH`m-xCR18%?B#ny_+rWOZ$<>m$#Mb7}vmeT$7U~rYvKK457ilDgzc?LH z>To-~%=p-p(xiEvz^2e}@cf6gh@O=F{N0s5-0&21REG%0=_+vq$E)J(pYD(d^f{jgCt$ zboojOc*`?PYn7)b)<%99xW3{YxAG4Ip6Cg;vos-def)eIWA4Fx*UZ_a`3CQuMNiCh zXY77JS^dK;E7_@LnP0iRIH)my|8FBI_jeCp-QTu`Ke08SWrwY>Yh!j!-#wl0?OzI_ zjB-+cF;_bld+g?-#~E7`8@)f8)dj^gFCWN1*5RO4w&JAcfgAQN8iXjn=!jsR%*AQo zk;hkyY(2;0J4P3D{}esbW{*mAfSvEMw|8U2E=!_ue#(p1KRs)xy=ty19<#Qvwr%3? zTJxg6WMiLATx-h(^}Me!2#Exik#2cJ>s^x<3es^hx+HK69clOwH%{Jtz+_{Oy2t0ek$r?#9gG%G}hM z-4&Z!T#ZxfE;w724?AOVU!+EjV6o3lpV_AOKX0!YvHUfn*xGz*Ti%?H>|uLh{F5>6 zc7fD3Zq=SIk4(}spL2X<0&$_yJ3Zgf8soJ`uT{Qp(2L3OJ$ZM}`W()h(bTAtX>%JR znnR|%UcGG(>r&JFqx1VB%^BYM7j4s2!vmbY1l$R1-!LS+IkdND!S-8T^D8bis5Y2N zxp8H-q(E8`n<(kSaalXgJ6LH)jdDUAcXm1Z4wdp_bi0l0xh8>lVwgQn9=L30rOmn1 zd+O|1U=>Fol}0Hzq!rqmCRaO3MtnV~v zEYp&TGbi3@+;rGAIJV_#5kg-GwWDBbkDbqms^`m63v2( z!ul*9^V+MuS^9rRy;eCrwdgX-Va^eyZ%NfM)ius1g`Gc7N*=OYEw32mcPL7w;|~aW zwkJDR?E~NSW3#o2Dj}PSZ>zs(oe^evsHj;`V3Ve`IQ+5t%RtBA+LKOMp3`*8o~g3Z zz9w0=wFgNFl@de7^>W;KZa04nO8pnJqDyuF literal 0 HcmV?d00001 diff --git a/include/limesurvey/admin/classes/phpCAS/docs/images/jasig.png b/include/limesurvey/admin/classes/phpCAS/docs/images/jasig.png new file mode 100644 index 0000000000000000000000000000000000000000..38952bd2f72dba1b6cd6d9fe0ee5ac9dd191ce87 GIT binary patch literal 2384 zcmZ9Odpr~R8^=eHODMVL(&-Q_x5#a7$03oL32jnX zjBt>#?VyD=#9R`VOEx7Oo%8#>ey`W>kLP(_-}m?XJm0^b*XNV*8~BWjl$sO(0FZHY zaq`@)RlDIUA-bEFjaCot7D>2^Ukm^s+xa6zdZI|zcA2QFlY@7B(GtWUiszzYc*^p4 z4baSu;;`*7nX)CV><0u<`aQF7gSjqlxU;@bfd(J(dwuX=F`a6cE9^8UY0;x%Ty2gm zZQtxdQcnQd{k-4Y+kaP4={dwNoTC&yt4Del-}neXqCx1 zUBx{jmov!=S3r~Qlar({51s7QdrylfMuKtr*3$ahnbEIk*Ev0pU@D}IWDTRe@Ad%C zfgH+ln>d6V;6O&=pI-T>Zso$3v@4)?i&C)%S5Dxo88G40cm8Q&Ootsj(1;us1v!wJ z>drMTZhHHhllsh4)6jMuMWH|6Cv!hw{D$3Rr4-i`8LB>KPP=*u-n&4Z2%xgK(FXPNob+L zwZMCp%=CF}mR27&)9CxwrrgL{jI|LDYFFONZ`iEpfCbA5V*sSN5)lB-Igljgy868i zr0z)>SNdtV{pp%2M@jkFtdH=apwtRSl211fMi;rs6fS3`Z&D?CH`3dW{Lv28QGo}M zsXgZG;4)QOmV=BCmwgGR!_ta)iLWeb_8uSZoYYKr1VF69i3QP5LScQy#}@ad*5brb zT~=&n1N=ztUxzL79l1f%^1oBHDh}0zy;{PoLuiTu^F}Wtp@{L{Au|;*A;0sC) z^*U7Lx|j9U7yT>oYCwTgYMdvsoVMZ?fOcCn5*~d)v};(c{{lNpuI2Epfi7y6dQ@d^ zPru_sy&pyP@n>XGHhpUv#^5A`{i}qsR$F&Cg7{jKKX;a&@b-ohgnrJ0A)hONUO0ii z^KG9rdUVflx?s7&)6Ze~tD& zJtajb%l=@_5G>WMX}rXKXUgn!lGJ6 zZ8$|}aTi&qk9Vz!HOYmGZu!0=5yFU!y%!j^V2|ZQs0BVMEomAT`()z%&_FTPqXVw`IHc@}ZN{5|5jk%tviR3P@{Z5A0&reN#&wd~*c1PX{ zml6CnHw^21Q&Wpt1V6S)=>N&?mi?X$)8q}O{Lu+qgilINLva2dO%l8NK>Fap?@01w z&`!FYq2%-=hYn~o&E2llRWo^&)GC^fMyLW>2Oe8TONupXohnm4Q#1-0P9v!^5hV$i0S^(Btah>}@msqGJ1hgGcF17zf(?QcgJtNa5h22P(>Njq`D|v$l zMHyd(IJaQ49vqa>c*YFf@Kh(@yT_H+{0(b|${m`4v9c86AkU3e9v6FkVCLVQ?{hpJ1QD;&qmg}cmTZ*3 z8lU_O6~+SI?(AJx=OXP2ZZ!|QNE(M43GHuak?+TYE}sl3R8&52kYYzHvC>b_U{LK9>Gvs9_}`JCV;uyIiq9~T#Q9(eAT_kf<2la%os)?G3q8#9;Z-66xf%ySd56g6 z++2kadf(U#JadHT=&F*`;wA2V*4Ra!BISswk z+keu}wc8r?h+)b;#XhAC*(PZooy%B2+oJ14lSgCmg6?S<@GAKJyM3sL&$a^9Hv2|i zUFkAc%d~}Sp*%irq5O}C?+QG!^Fl5f{I1c@*H x*A|f19!VPs|K&fXM1B5oX54vzlC$342fj8wLuVK*>{=v%>uIplvtKW#{0&y?&jtVh literal 0 HcmV?d00001 diff --git a/include/limesurvey/admin/classes/phpCAS/docs/images/phpcas.png b/include/limesurvey/admin/classes/phpCAS/docs/images/phpcas.png new file mode 100644 index 0000000000000000000000000000000000000000..bb3d8f06b8817205c9463107a25b549c074bd83a GIT binary patch literal 6771 zcmbVR^-~;88zi^{cMT39Xb8>`+})kvfgr)*umCyST@QD6cMI1ymGhMyi{XAP6rm8H1iB5(N2M32KCo8EATf1RH5)~dcn{2p5z!tQhvU)CXa2R<1 zjd!yfe$Q}lWQ=l>Vw#?rXPMrb_)A^G0d0w=d-I<hU3p+DiU3GhBApr}Zht7-HEGGF5bf_S(8qP^$({o5KzQIfheCTN$A7hS$w zDs=tp!I$U+xzA_~ogS4wORqsZXPy4uR{jqYj&FBVK0}??qZ*ITiwKt|Z?zpz&;8c_ ze`4<3(Wi8OCp{_<8XA(wKwCKSr<9v4X_W_XCm5X+hd5b%lB()6S#7nMOAoX^|yPb4vOZP{c{=z1lN&*wd$c2?5q@ z!>4W`7@r}ybR)dElOjGNjJG0NZNW`#A=h90O7rN2eu$-{%VRCiT~N#J<^^b%yIK6b zn%+jJUvaK{OCDLShJ0>pzPI`Eq;L5nNmqkmF_XP|YE0wr{>QpH2ECQ|ewpch8P(^* z4&lKOc(?r}duP3N?WH+iryes>GE%SSPmvv>^G)$_w4@(|-Ar=X9nKVP*h;xT+ z8%2OneC6?;TOouc$nv_PhD){KqVc2K+6esZOlEK-U74$x{irbmhu)-|k3LS<*$V9- z#<&DNzm{UlHFq*IOOvaICN2S(7~axhE3KA|*==~T)6~?4Gt&k7z148@+vhu#%mUQE z-8uuH|3JvKtqrs=AMjRz;-5(XWL8pS1elwf_xFF@6+vb? zI4LC0GJ4VVRe`-D85gpR(<%Lr1;DSK;UU_GXv<=U?x_4g#i_lvTLh zqobutYf#@A7|yz&X|$i&PUq+Z>M%ushyU=(e@YOIS+J#~dUe`xUTs<5-ML0Ua+?Cc^Bd^<<@MTjY!#j(i+j2LGZ%#jJLR85~aK=I$1GvcWt9>EGO z5>^=GKAd{c5)$&vX&0ohj*p7ueFgViBM9#)ho))NE+`S(FzpKptThwmY%Im0k&(hw zEq*dvmVF8uE*ux;o+I)^v|-i?csSNAI2agl)ILZ|S2n#Hc=o@}p7BjaHQF4Si9{7R{E9kW3;P!`a{14;6eRME!WIH}OZqc+zF2%rYZdnltNs& zrD6-j!`&N_AT=fMTS{&U>3jKD+%i-)(Kovmv3OXGQss!t*CSthB|Ieo=_IjJ9(Lrr zFJHTB3Mjhj3KyWog^sMcoLkxj>Xwf>8&{lyTtHM3hJ~MaglL&%C4i7-Kb$tF{->NA zdowQiw)S^7mp9uO@<8p+bq)eQ1@4|Ug-J$b*Wc%**I=b2X^_UP0)yTY#^GNtG@UW&jERYeLr9RF5*P}{y{VL=5M~38TPY;z z1|9m(AvJR9q;rz4Z!>_|O2wmC86#w;yfb)BSu}*b<0-Mzatp{D)a@-?FUl4o85D?6 zP*A$bomO!H&ExFw_EWAT@_7Y^ZMlx?T!56?dgZ495^_qZ3H$B+(>~v?B!=CJ$A5SL z8^kDfk0vmy21syWa_Wrk%4QO${+pV|Dz&E|uN-{ZTx$rE#f}&$Be);pEI&`zP!+;G zMK$SFstRhg=6zH7+X3>=#H#yvymCLr55}r+!(O&hnbP@l=n2wROG1IVVqgp8qD~ zgAtrA@p5iNap~9u&3>gSqwd>K zI-nqC!(HYEVG6E<+>~!UQuTBYkNT`Rju!v%9asz!Pi5A0DF~g6W%d~N>EE~#$}cW$ z<>RR|q%P^fABfH)GEG+AvSeXpby5$HQ24|$&^W4HIjIXGo4YIDU1q-EoxLl!O{#o- zowGZ7czU|_^7(h*>=jg0Tii5BKR!EH&%mjI?o#M|Z$2@B{IpmYu7L7+-pOwMBAURl zLq}Y0%AebL!?(g!^CN2n;@bIf90rEH8^ugetA2wCZq_yRk`MXn15SC7KL*zEj7OSh zSYfHn{yKeFf~(2<`nIAAc`K`AY|M#NuD!-3W2tWitt+bPR-xwktdj8w_x7fyXjum^ zY(%W7A1EkTQ~2hyJKwt$UUBNHTj8K$&Dw~#97Gm6c2N-%muolY)QJ$$(sZJjJh)IX z0OJ0TK4B*oU8F&ze^K5+DZc&2FUKSS0`jeWd^&U&^lAY$a1*Dc5ndRPP}HK~9w+C3Rk&`}jN}!E`>z;3SsssvjZCsSB~l zhY#6@)^AmH-b1JOruW}U7@;a#h>O`J7z zU@!+wI3Ox)I_R`3w;Uzx>RSqwi_v|P8wtQxS@h?~kgB82+WuoHaHLxzZ)4TmW0NKgEED4=ukLv6fkhBQ;hB&gR3~kisH+!9(?VH;^(cp> zVa69W=-c^}q3;lH`}FXjsTsO(LbRJC;9_;!0901T^edqQvxS-Gdp%Opsxg$>ySrl* zk@348pbJ?=3vRz4C_4;KbA#b2aDK)+Pwfk%*d zp}6Y7stU(nW#_O#!7R3s0|$vz?9|_seSLLaR>n>jt7wd^x%9M3;w-WTbBhkA zbLsX?-1eaSVd;mRcqiAwIC8_Fh0fsef{4oHW+6D}*v!qe&%dhP?L~h3wy3joWLUu}npy#GPZ`1BK9K~NX+Ur1}R zTT!fNG8>d{9MaVB2q3`yAmlF0k!=S6vweIkTN7c^)Yk_m+*elC(EefnbHo&{-JUlzwQ3}K_ zQPOxWwJoE04xk_)gGJX@BV!fA3#BYUDRxI$;>^MZB#GrU|ktA`jdnlHBkSy|cELj6=(wQm)}tynC=K z|A0IJhlh{nezus2O8V2FZ-M02dMn3wH^B2>GBY6Afn2NH=-r*jY#V_2J9#kA)8pex z)p$BjdG3y(vwjvEMx-}?W1HoZtH0TrL`d|P#`W>ZNgCr!K8RFhRY*pG&yb+bs7mP% zM+lu)X-|(OTP5S}!Nw5fe)N$ZD%P1;83iRKcScAZNPV~TVXx2n`i1DGGp5%;9;iv{ z#k4pJ;>jLP|F~q>sY|B>Wa%~F2Rxu*@|b6-Jv_$lbhx;}#BXHDT3B!>VjgzW1fIhm zmL}wpRtKk$-0c2SRn!fHSj7^_z-$B)fU{9`=Uth$wc@rg052wll~%2=8ZuXJ{$NI~ zff<{uR<2X2p2ag%@82|;P=_P;zMf12bGf@oU0q%FYK3Z%lnJ`cq+uTC7%s)eqwB%8 z808<Vr z_27C0DDsAm1altq(C@M|jEsc8FzFm0SRWn3J}&-EMsBD{J*2QtD!|JWEvCLUKrwd{ zC4Yx3%^R80es+kD&o)eGGD(6dv#7Q^Ph8PQVkbwpQhT=jY%fNHK4hFz|5fY0%lCM| zRw0@7;_Rflk~=Qh8|G^DL595B{8oD5bK*b^Mi z;Kz&sK@mjUMCdyARu(I;$~2V@D7;omA{}Uibw&zgP0lsKT~YOYITVTax zFFPzQkS1U|XQEAeNu%73jfEWp3yZM`--(bYSu@;QPJz3F)wlUuAap?71Si{;KS)7N zrLZOvOAw}7>sVKL;OcJ`UkUuaG)W+GuAA#CZXfr5#dp5p`do;6*>L``4#Phe7QA5` z1h7&|%58;+IG!fN_w8c+7p%S&d_zjf&W6;Q55qEAJB)|E3}(%kgC^V<2tBoW;}8K! zOC%!cX6F3Yk*D#rDf$$-iK}W5GvuPu9mP5t|Z2kPYU~MDRf35v4 zwWx}7(;^)w(x9KH{=1nhFMgp@TS?p(#H?TFPSoMbl~MEPHe+)l7oF$l2!trYsF;_5ILUBn}f*eT`B`)DoQX*Ak2vSMFPh=L7`NVhNd^o{HZ@0#&VD2EEQ zkhN3Mfww0Mu_I)ffGr5^p7iUf4{x64xaJg(fJgE_FJP(DGHl*h(5RLwIq>)(bb10*iH`*fR7_`J%XN27!^~+$`Xc)jc+{y z@BwfVm)Vp4Uy6FKSzJWc)lr)X`dN6_#{(QcC4S9N>=rM{@j5x z>&El?$QW2+ZFh!*xR8}Qx)RG$@{9U)J{S-GW{3-&Fvs`BKXn{| zGAn3~f;TnT^}JuH`5*fTn_USeqPxJ)H9j{ZzkXyP!T<0++lKh3rec`yf9}sP;s0JM zSjD%@ri~ItaOl`sQQ-q#JS?ag@DXWtKVL0bUe-Ny4R=BeKm{8tZ@hd0u>i6S$X(xd zuWJ>YF@lestVuz6rA1YTwAE1&--}Sqx25>V)%Tv?W33N?YM1D6G0AN))>TCZQ27)M zZO@KL`ve9jCMp9Kdp|vip4Ol1nIS})W$-y7bbn7f+&k}!^qPo@TGc34&_%-JEbB)@ zP0ZTc?U3=+-F$0lcGzgEsxnD-pu}y&7R9?`+z-5ulU5$AHI5kIl7Udv zMo~dh(qo7F2j|Iwwa^t7=k*IGYHH+DvY6_-M^R!g`ywnEdFS}IXG<$9lE~$h0)zX#PTGB%Da_sTHF?7j|p2czGg$4-g%jjII#8 z8CXyHV_dCMew;hAPf(VqHQggtl(|?}=N$HdmB@f!-*|hWe|Vr!y1f$H+P7?H=s8+b zgjPIDc6B6J^ILOxbaea(OY%-`H+QNdHsU#%9X^63IxG;3ubo7_5*_SF1Kc#Og~EnCg(9WcscwV2`ad zPdl7``e=V`Qxcm08*zCw5tnxUYEW9!>@Tecv!=~%*B6+NttPxJoCDQM(a+}$?R9;o z=0`?S+zql77Zr5V`3E@IzOmOCLlG6Fk6MOMjtgS3Bo5*@$=I)mYznLtDE_^^4ounR4+D2E&8fN%O~x!)s4Q*yac? zbVL#7+6k>)##&B~$g!G!T~PQe;=~4*3Q^}}iZDraBO{laBKUqN_6Mk7R#hl*$MeHi z2r?AdNi|il2Doqr_zONQB{1dJySPG2=Z?w9y?3q@rIVABekD2ATOc~p(Vm2TyL!OZ YL&(hT=*%gA{Y8S4lTwzf68{$XKmMga_5c6? literal 0 HcmV?d00001 diff --git a/include/limesurvey/admin/classes/phpCAS/docs/index.html b/include/limesurvey/admin/classes/phpCAS/docs/index.html new file mode 100644 index 00000000..d9925bb8 --- /dev/null +++ b/include/limesurvey/admin/classes/phpCAS/docs/index.html @@ -0,0 +1,19 @@ + + + + + phpCAS + + +

+

phpCAS documentation is hosted at https://wiki.jasig.org/display/CASC/phpCAS.

+ +

+

 

+ + + From cc0cac28525b32a822f313a783161bea1939a599 Mon Sep 17 00:00:00 2001 From: Adam Zammit Date: Fri, 18 Dec 2015 15:37:15 +1100 Subject: [PATCH 4/4] Got CAS authentication working (basic) --- include/limesurvey/admin/login_check_cas.php | 278 +++++-------------- 1 file changed, 76 insertions(+), 202 deletions(-) diff --git a/include/limesurvey/admin/login_check_cas.php b/include/limesurvey/admin/login_check_cas.php index 9027cd52..8ebb6690 100644 --- a/include/limesurvey/admin/login_check_cas.php +++ b/include/limesurvey/admin/login_check_cas.php @@ -23,218 +23,92 @@ if(!isset($_SESSION['CASauthenticated']) || (isset($_SESSION['CASauthenticated'] //echo "bla"; // import phpCAS lib include_once('classes/phpCAS/CAS.php'); - include_once("classes/phpCAS/cas_config.php"); - if(isset($_GET['user'])) + + +// phpCAS::setDebug(); + + + phpCAS::client(CAS_VERSION_2_0, $casAuthServer,$casAuthPort, $casAuthUri); + + phpCAS::setNoCasServerValidation(); + + if (isset($_REQUEST['action']) && $_REQUEST['action']=='logout') { - $token = $_GET['token']; - $user = $_GET['user']; + phpCAS::handleLogoutRequests(); + //session_unset(); + phpCAS::logout(); + session_destroy(); + session_write_close(); + //phpCAS::forceAuthentication(); + } + else + { + // force CAS authentication + $auth = phpCAS::forceAuthentication(); - $action = getGet('action'); - $siddy = getGet('sid'); - - $get = '?'; - if($action!=FALSE) - $get .= "action=".$action."&"; - if($siddy!=FALSE) - $get .= "sid=".$siddy."&"; - - if($user == verifyToken($token) && verifyToken($token) != null) + if($auth) { - $auth = TRUE; - //setUserRightsCas($user); - $_SESSION['CASauthenticated'] = $auth; - header("Location: admin.php$get"); + + $query = "SELECT uid, users_name, password, one_time_pw, dateformat, full_name, htmleditormode, questionselectormode, templateeditormode FROM ".db_table_name('users')." WHERE users_name=".$connect->qstr(phpCAS::getUser()); + $ADODB_FETCH_MODE = ADODB_FETCH_ASSOC; //Checked + $result = $connect->SelectLimit($query, 1) or safe_die ($query."
".$connect->ErrorMsg()); + if(!$result) + { + echo "
".$connect->ErrorMsg(); + } + if ($result->RecordCount() < 1) + { + // wrong or unknown username + $loginsummary = sprintf($clang->gT("No user"))."
"; + if ($sessionhandler=='db') + { + adodb_session_regenerate_id(); + } + else + { + session_regenerate_id(); + } + } + else + { + + $srow = $result->FetchRow(); + $_SESSION['user'] = $srow['users_name']; + $_SESSION['checksessionpost'] = sRandomChars(10); + $_SESSION['loginID'] = $srow['uid']; + $_SESSION['dateformat'] = $srow['dateformat']; + $_SESSION['htmleditormode'] = $srow['htmleditormode']; + $_SESSION['questionselectormode'] = $srow['questionselectormode']; + $_SESSION['templateeditormode'] = $srow['templateeditormode']; + $_SESSION['full_name'] = $srow['full_name']; + GetSessionUserRights($_SESSION['loginID']); + + $auth = TRUE; + $_SESSION['CASauthenticated'] = $auth; + + //go to queXS + $loc = ""; + if ($_SESSION['USER_RIGHT_SUPERADMIN'] == 1) + $loc = "admin"; + else + { + $utest = $connect->GetOne("SELECT username FROM client WHERE username = '" . $_SESSION['user'] . "'"); + if (!empty($utest)) + $loc = "client"; + } + header('Location: ' . QUEXS_URL . $loc); + die(); + + } + } else { $auth = FALSE; $_SESSION['CASauthenticated'] = $auth; - header("Location: http://$casAuthServer$casAuthUri&category=auth.login"); } - }elseif(!isset($_SESSION['CASauthenticated'])) - { - header("Location: http://$casAuthServer$casAuthUri&category=auth.login"); - } - if (isset($_REQUEST['action']) && $_REQUEST['action']=='logout') - { - //session_unset(); - session_destroy(); - session_write_close(); - //phpCAS::logout(); - //phpCAS::forceAuthentication(); - header("Location: http://$casAuthServer$casAuthUri&category=auth.logout"); - } - - //if ($action=='login') - if (isset($_REQUEST['action']) && $_REQUEST['action']=='login') - { - //phpCAS::forceAuthentication(); - header("Location: http://$casAuthServer$casAuthUri&category=auth.login"); - } - if($_SESSION['CASauthenticated']===FALSE) - { - header("Location: http://$casAuthServer$casAuthUri&category=auth.login"); - } - -} -if(isset($_GET['token'])) -{ - - $action = getGet('action'); - $siddy = getGet('sid'); - - $get = '?'; - if($action!=FALSE) - $get .= "action=".$action."&"; - if($siddy!=FALSE) - $get .= "sid=".$siddy."&"; - - - header("Location: admin.php$get"); - -} - -function getGet($var) -{ - switch ($var){ - case "all": - foreach($_GET as $get) - { - return; - } - break; - default: - if(isset($_GET["$var"])) - { - return $_GET["$var"]; - } - else return FALSE; - break; - - } -} -function verifyToken($token) { - global $singleSignOnService, $singleSignOnSharedSecret; - - // check the configuration options in LocalSettings.php - //QISSingleSignOn::checkConfiguration(); - - //echo ('QISSingleSignOn: token:'.htmlspecialchars($token)); - - // prepare token - $tokens = explode('/', $token, 4); - if ((count($tokens) != 4) or (strpos($tokens[3], '/') === false)) { - echo ('QISSingleSignOn: Token incomplete:'.htmlspecialchars($token)); - return null; - } - - // find the _last_ '/' to split username and hash as the username may include '/'-chars. - $temp_pos = strrpos($tokens[3], '/'); - $tokens[4] = substr($tokens[3], $temp_pos + 1); - $tokens[3] = substr($tokens[3], 0, $temp_pos); - - // check version - if ($tokens[0] != '1.0') { - echo ('QISSingleSignOn: Unknown version:'.htmlspecialchars($tokens)); - return null; - } - - // check time - $currentTime = microtime(); - $currentTime = substr($currentTime, strpos($currentTime, ' ')); - if (intval($tokens[1]) > intval($currentTime) + 60) { - echo ('QISSingleSignOn: Token was created in the future (Check your clocks):'.htmlspecialchars($token)); - return null; - } - if (intval($tokens[1]) + 60 < intval($currentTime)) { - echo ('QISSingleSignOn: Token expired:'.htmlspecialchars($token)); - return null; - } - - // check service name - if ($tokens[2] != $singleSignOnService) { - echo ('QISSingleSignOn: Wrong service:'.htmlspecialchars($token)); - return null; - } - - // check username name (using Title::newFormText as in User::newFromName) - $userinfo = explode('/', urldecode($tokens[3])); - - // Andere Methode wie bei tokens: find the _last_ '/' to split username and hash as the username may include '/'-chars. - // $temp_pos = strrpos($tokens[3], '/'); - // $userinfo[1] = substr($tokens[3], $temp_pos + 1); - // $userinfo[0] = substr($tokens[3], 0, $temp_pos); - - // echo ('QISSingleSignOn: userinfo-0:'.$userinfo[0]."\n"); - // echo ('QISSingleSignOn: userinfo-1:'.$userinfo[1]."\n"); - - //$t = Title::newFromText($userinfo[0]); - - $user = $userinfo[0]; - if ($user == null) { - echo ('QISSingleSignOn: Invalid character in user name: '.htmlspecialchars($userinfo[0])); - return null; - } - - // check hash - $toHash = $tokens[0].'/'.$tokens[1].'/'.$tokens[2].'/'.$tokens[3].'/'.$singleSignOnSharedSecret; - $hash = md5($toHash); - if ($hash != $tokens[4]) { - echo ('QISSingleSignOn: Hash verification failed:'.htmlspecialchars($token).' Should be: ' . $hash); - return null; - } - - // copy _ridlist to session for WikiRights (if present) - if (count($userinfo) > -1) { - //session_start(); - setUserRightsCas($user, $user); - //$_SESSION['_ridlist'] = $userinfo[1]; - } - - // welcome, you passed all tests. - return $user; -} - -function setUserRightsCas($user, $role="") -{ - include_once("../config-defaults.php"); - //include("../config.php"); //Not needed since config-defaults includes config.php - - $_SESSION['user'] = $user; - $_SESSION['loginID'] = 1; - $_SESSION['dateformat'] = 1; - - $_SESSION['adminlang'] = $defaultlang; - $_SESSION['htmleditormode'] = 'default'; - $_SESSION['questionselectormode'] = 'default'; - $_SESSION['templateeditormode'] = 'default'; - $_SESSION['checksessionpost'] = sRandomChars(10); - $_SESSION['pw_notify']=false; - - switch ($role){ - case "admin": - //echo "hallo"; - $_SESSION['USER_RIGHT_CREATE_SURVEY'] = 1; - $_SESSION['USER_RIGHT_CONFIGURATOR'] = 1; - $_SESSION['USER_RIGHT_CREATE_USER'] = 1; - $_SESSION['USER_RIGHT_DELETE_USER'] = 1; - $_SESSION['USER_RIGHT_SUPERADMIN'] = 1; - $_SESSION['USER_RIGHT_MANAGE_TEMPLATE'] = 1; - $_SESSION['USER_RIGHT_MANAGE_LABEL'] = 1; - break; - default: - //echo "default"; - $_SESSION['USER_RIGHT_CREATE_SURVEY'] = 1; - $_SESSION['USER_RIGHT_CONFIGURATOR'] = 1; - $_SESSION['USER_RIGHT_CREATE_USER'] = 0; - $_SESSION['USER_RIGHT_DELETE_USER'] = 0; - $_SESSION['USER_RIGHT_SUPERADMIN'] = 0; - $_SESSION['USER_RIGHT_MANAGE_TEMPLATE'] = 1; - $_SESSION['USER_RIGHT_MANAGE_LABEL'] = 1; - - break; - } + } }