(As suggested, I'm moving the discussion to debian-lts@lists.debian.org, CC'ing the security team)
> On 19/06/2023 18:17, Tobias Frost wrote: > > Hey, > > > > As I am currently preparing a fix for php-cas to tackle CVE-2022-39369 [1], > > and > > as the changes required are breaking changes, I'd like to discuss whether > > the > > vulnerability justifies a breaking change, or if the issue should be > > ignored instead. > > (Maybe feedback from interested customers can be collected, so that they > > can assess > > the impact on their side already.) > > > > I've packaged my backport of the patch and uploaded it to [3] as an > > (untested) preview. > > > > The breaking change: users of php-cas needs to perform additional steps when > > using the php module, as described in docs/updating of the upstream pull > > request fixing the issue: [2] > > > > phpCAS now requires an additional service base URL argument when > > constructing the client class, similar to other CAS client's > > serverName config. > > > > Upstream asses the situation as [4] > > > > This vulnerability may allow an attacker to gain access to a victim's > > account > > on a vulnerable CASified service without victim's knowledge, when the > > victim > > visits attacker's website while being logged in to the same CAS server. > > The patch applied to the package is this commit: https://salsa.debian.org/lts-team/packages/php-cas/-/commit/2c2b5f73da55f5c6d9f69e1ac11b3a1ee565d435 (also debdiff attached.) -- Cheers, tobi
diff -Nru php-cas-1.3.6/debian/changelog php-cas-1.3.6/debian/changelog --- php-cas-1.3.6/debian/changelog 2019-02-10 09:29:07.000000000 +0100 +++ php-cas-1.3.6/debian/changelog 2023-06-19 17:12:56.000000000 +0200 @@ -1,3 +1,10 @@ +php-cas (1.3.6-1+deb10u1) buster-security-UNRELEASED; urgency=medium + + * Non-maintainer upload by the LTS Security Team. + * Backport patch for CVE-2022-39369. + + -- Tobias Frost <t...@debian.org> Mon, 19 Jun 2023 17:12:56 +0200 + php-cas (1.3.6-1) unstable; urgency=medium * Update debian/watch diff -Nru php-cas-1.3.6/debian/patches/CVE-2022-39369.patch php-cas-1.3.6/debian/patches/CVE-2022-39369.patch --- php-cas-1.3.6/debian/patches/CVE-2022-39369.patch 1970-01-01 01:00:00.000000000 +0100 +++ php-cas-1.3.6/debian/patches/CVE-2022-39369.patch 2023-06-19 17:12:56.000000000 +0200 @@ -0,0 +1,954 @@ +From b759361d904a2cb2a3bcee9411fc348cfde5d163 Mon Sep 17 00:00:00 2001 +From: Phy <g...@phy25.com> +Date: Mon, 31 Oct 2022 16:34:25 -0400 +Subject: [PATCH] Merge pull request from GHSA-8q72-6qq8-xv64 + +* Add ServerName classes and required service_name constructor argument + +This includes a refactoring of moving Client->_getClientUrl() method to a new class. + +Unit tests are also added and updated for the new constructor argument. + +* Add service_name argument to the static helper class and examples + +* Update docs for 1.6.0 release + +* Update versions for the 1.6.0 release + +* Rename ServerName class to ServiceBaseUrl and add protocol in allowedlist check + +* Update docs for the ServiceBaseUrl class and argument change + +* Minor typo fixes +--- + docs/ChangeLog | 31 ++- + docs/Upgrading | 34 +++ + docs/examples/config.example.php | 3 + + docs/examples/create_pgt_storage_db_table.php | 2 +- + docs/examples/example_advanced_saml11.php | 2 +- + docs/examples/example_custom_urls.php | 2 +- + docs/examples/example_gateway.php | 2 +- + docs/examples/example_hardening.php | 2 +- + docs/examples/example_html.php | 2 +- + docs/examples/example_lang.php | 2 +- + docs/examples/example_logout.php | 2 +- + .../examples/example_no_ssl_cn_validation.php | 2 +- + docs/examples/example_pgt_storage_db.php | 2 +- + docs/examples/example_pgt_storage_file.php | 2 +- + docs/examples/example_proxy_GET.php | 2 +- + docs/examples/example_proxy_POST.php | 2 +- + docs/examples/example_proxy_rebroadcast.php | 2 +- + docs/examples/example_proxy_serviceWeb.php | 2 +- + .../example_proxy_serviceWeb_chaining.php | 2 +- + docs/examples/example_renew.php | 2 +- + docs/examples/example_service.php | 2 +- + docs/examples/example_service_POST.php | 2 +- + .../examples/example_service_that_proxies.php | 2 +- + docs/examples/example_simple.php | 2 +- + source/CAS.php | 26 +- + source/CAS/Client.php | 109 ++++---- + .../ServiceBaseUrl/AllowedListDiscovery.php | 152 +++++++++++ + source/CAS/ServiceBaseUrl/Base.php | 98 +++++++ + source/CAS/ServiceBaseUrl/Interface.php | 61 +++++ + source/CAS/ServiceBaseUrl/Static.php | 69 +++++ + test/CAS/Tests/AuthenticationTest.php | 1 + + test/CAS/Tests/CallbackTest.php | 1 + + test/CAS/Tests/Cas20AttributesTest.php | 1 + + test/CAS/Tests/LogTest.php | 2 + + test/CAS/Tests/ProxyTicketValidationTest.php | 1 + + test/CAS/Tests/ServiceBaseUrlTest.php | 244 ++++++++++++++++++ + test/CAS/Tests/ServiceMailTest.php | 1 + + .../CAS/Tests/ServiceTicketValidationTest.php | 1 + + test/CAS/Tests/ServiceWebTest.php | 1 + + utils/version.properties | 2 +- + 40 files changed, 789 insertions(+), 91 deletions(-) + create mode 100644 source/CAS/ServiceBaseUrl/AllowedListDiscovery.php + create mode 100644 source/CAS/ServiceBaseUrl/Base.php + create mode 100644 source/CAS/ServiceBaseUrl/Interface.php + create mode 100644 source/CAS/ServiceBaseUrl/Static.php + create mode 100644 test/CAS/Tests/ServiceBaseUrlTest.php + +--- a/source/CAS/Client.php ++++ b/source/CAS/Client.php +@@ -896,6 +896,14 @@ + * @param bool $changeSessionID Allow phpCAS to change the session_id + * (Single Sign Out/handleLogoutRequests + * is based on that change) ++ * @param string|string[]|CAS_ServiceBaseUrl_Interface ++ * $service_base_url the base URL (protocol, host and the ++ * optional port) of the CAS client; pass ++ * in an array to use auto discovery with ++ * an allowlist; pass in ++ * CAS_ServiceBaseUrl_Interface for custom ++ * behavior. Added in 1.6.0. Similar to ++ * serverName config in other CAS clients. + * + * @return a newly created CAS_Client object + */ +@@ -905,6 +913,7 @@ + $server_hostname, + $server_port, + $server_uri, ++ $service_base_url, + $changeSessionID = true + ) { + // Argument validation +@@ -921,6 +930,8 @@ + if (gettype($changeSessionID) != 'boolean') + throw new CAS_TypeMismatchException($changeSessionID, '$changeSessionID', 'boolean'); + ++ $this->_setServiceBaseUrl($service_base_url); ++ + 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 +@@ -1007,7 +1018,7 @@ + + if ( $this->_isCallbackMode() ) { + //callback mode: check that phpCAS is secured +- if ( !$this->_isHttps() ) { ++ if ( !$this->getServiceBaseUrl()->isHttps() ) { + phpCAS::error( + 'CAS proxies must be secured to use phpCAS; PGT\'s will not be received from the CAS server' + ); +@@ -2363,8 +2374,7 @@ + if ( empty($this->_callback_url) ) { + $final_uri = ''; + // remove the ticket if present in the URL +- $final_uri = 'https://'; +- $final_uri .= $this->_getClientUrl(); ++ $final_uri = $this->getServiceBaseUrl()->get(); + $request_uri = $_SERVER['REQUEST_URI']; + $request_uri = preg_replace('/\?.*$/', '', $request_uri); + $final_uri .= $request_uri; +@@ -3528,10 +3538,7 @@ + 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(); ++ $final_uri = $this->getServiceBaseUrl()->get(); + $request_uri = explode('?', $_SERVER['REQUEST_URI'], 2); + $final_uri .= $request_uri[0]; + +@@ -3568,66 +3575,62 @@ + return $this->_server['base_url'] = $url; + } + +- + /** +- * Try to figure out the phpCas client URL with possible Proxys / Ports etc. ++ * The ServiceBaseUrl object that provides base URL during service URL ++ * discovery process. ++ * ++ * @var CAS_ServiceBaseUrl_Interface ++ * ++ * @hideinitializer ++ */ ++ private $_serviceBaseUrl = null; ++ ++ ++ /** ++ * Answer the CAS_ServiceBaseUrl_Interface object for this client. + * +- * @return string Server URL with domain:port ++ * @return CAS_ServiceBaseUrl_Interface + */ +- private function _getClientUrl() ++ public function getServiceBaseUrl() + { +- $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 (empty($this->_serviceBaseUrl)) { ++ phpCAS::error("ServiceBaseUrl object is not initialized"); + } +- 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; ++ return $this->_serviceBaseUrl; + } + + /** +- * This method checks to see if the request is secured via HTTPS ++ * This method sets the service base URL used during service URL discovery process. ++ * ++ * This is required since phpCAS 1.6.0 to protect the integrity of the authentication. ++ * ++ * @since phpCAS 1.6.0 ++ * ++ * @param $name can be any of the following: ++ * - A base URL string. The service URL discovery will always use this (protocol, ++ * hostname and optional port number) without using any external host names. ++ * - An array of base URL strings. The service URL discovery will check against ++ * this list before using the auto discovered base URL. If there is no match, ++ * the first base URL in the array will be used as the default. This option is ++ * helpful if your PHP website is accessible through multiple domains without a ++ * canonical name, or through both HTTP and HTTPS. ++ * - A class that implements CAS_ServiceBaseUrl_Interface. If you need to customize ++ * the base URL discovery behavior, you can pass in a class that implements the ++ * interface. + * +- * @return bool true if https, false otherwise ++ * @return void + */ +- private function _isHttps() ++ private function _setServiceBaseUrl($name) + { +- if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { +- return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); +- } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) { +- return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https'); +- } elseif ( isset($_SERVER['HTTPS']) +- && !empty($_SERVER['HTTPS']) +- && strcasecmp($_SERVER['HTTPS'], 'off') !== 0 +- ) { +- return true; ++ if (is_array($name)) { ++ $this->_serviceBaseUrl = new CAS_ServiceBaseUrl_AllowedListDiscovery($name); ++ } else if (is_string($name)) { ++ $this->_serviceBaseUrl = new CAS_ServiceBaseUrl_Static($name); ++ } else if ($name instanceof CAS_ServiceBaseUrl_Interface) { ++ $this->_serviceBaseUrl = $name; ++ } else { ++ throw new CAS_TypeMismatchException($name, '$name', 'array, string, or CAS_ServiceBaseUrl_Interface object'); + } +- return false; +- + } + + /** +--- /dev/null ++++ b/source/CAS/ServiceBaseUrl/AllowedListDiscovery.php +@@ -0,0 +1,152 @@ ++<?php ++ ++/** ++ * Licensed to Jasig under one or more contributor license ++ * agreements. See the NOTICE file distributed with this work for ++ * additional information regarding copyright ownership. ++ * ++ * Jasig licenses this file to you under the Apache License, ++ * Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * PHP Version 7 ++ * ++ * @file CAS/ServiceBaseUrl/AllowedListDiscovery.php ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++ ++/** ++ * Class that gets the service base URL of the PHP server by HTTP header ++ * discovery and allowlist check. This is used to generate service URL ++ * and PGT callback URL. ++ * ++ * @class CAS_ServiceBaseUrl_AllowedListDiscovery ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++class CAS_ServiceBaseUrl_AllowedListDiscovery ++extends CAS_ServiceBaseUrl_Base ++{ ++ private $_list = array(); ++ ++ public function __construct($list) { ++ if (is_array($list)) { ++ if (count($list) === 0) { ++ throw new CAS_InvalidArgumentException('$list should not be empty'); ++ } ++ foreach ($list as $value) { ++ $this->allow($value); ++ } ++ } else { ++ throw new CAS_TypeMismatchException($list, '$list', 'array'); ++ } ++ } ++ ++ /** ++ * Add a base URL to the allowed list. ++ * ++ * @param $url protocol, host name and port to add to the allowed list ++ * ++ * @return void ++ */ ++ public function allow($url) ++ { ++ $this->_list[] = $this->removeStandardPort($url); ++ } ++ ++ /** ++ * Check if the server name is allowed by configuration. ++ * ++ * @param $name server name to check ++ * ++ * @return bool whether the allowed list contains the server name ++ */ ++ protected function isAllowed($name) ++ { ++ return in_array($name, $this->_list); ++ } ++ ++ /** ++ * Discover the server name through HTTP headers. ++ * ++ * We read: ++ * - HTTP header X-Forwarded-Host ++ * - HTTP header X-Forwarded-Server and X-Forwarded-Port ++ * - HTTP header Host and SERVER_PORT ++ * - PHP SERVER_NAME (which can change based on the HTTP server used) ++ * ++ * The standard port will be omitted (80 for HTTP, 443 for HTTPS). ++ * ++ * @return string the discovered, unsanitized server protocol, hostname and port ++ */ ++ protected function discover() ++ { ++ $isHttps = $this->isHttps(); ++ $protocol = $isHttps ? 'https' : 'http'; ++ $protocol .= '://'; ++ 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 $protocol . $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]; ++ } ++ ++ $server_url .= ':'; ++ $server_url .= $server_port; ++ } ++ return $protocol . $server_url; ++ } ++ ++ /** ++ * Get PHP server base URL. ++ * ++ * @return string the server protocol, hostname and port ++ */ ++ public function get() ++ { ++ phpCAS::traceBegin(); ++ $result = $this->removeStandardPort($this->discover()); ++ phpCAS::trace("Discovered server base URL: " . $result); ++ if ($this->isAllowed($result)) { ++ phpCAS::trace("Server base URL is allowed"); ++ phpCAS::traceEnd(true); ++ } else { ++ $result = $this->_list[0]; ++ phpCAS::trace("Server base URL is not allowed, using default: " . $result); ++ phpCAS::traceEnd(false); ++ } ++ return $result; ++ } ++} +--- /dev/null ++++ b/source/CAS/ServiceBaseUrl/Base.php +@@ -0,0 +1,98 @@ ++<?php ++ ++/** ++ * Licensed to Jasig under one or more contributor license ++ * agreements. See the NOTICE file distributed with this work for ++ * additional information regarding copyright ownership. ++ * ++ * Jasig licenses this file to you under the Apache License, ++ * Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * PHP Version 7 ++ * ++ * @file CAS/ServiceBaseUrl/Base.php ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++/** ++ * Base class of CAS/ServiceBaseUrl that implements isHTTPS method. ++ * ++ * @class CAS_ServiceBaseUrl_Base ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++abstract class CAS_ServiceBaseUrl_Base ++implements CAS_ServiceBaseUrl_Interface ++{ ++ ++ /** ++ * Get PHP server name. ++ * ++ * @return string the server hostname and port of the server ++ */ ++ abstract public function get(); ++ ++ /** ++ * Check whether HTTPS is used. ++ * ++ * This is used to construct the protocol in the URL. ++ * ++ * @return bool true if HTTPS is used ++ */ ++ public function isHttps() { ++ if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])) { ++ return ($_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https'); ++ } elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTOCOL'])) { ++ return ($_SERVER['HTTP_X_FORWARDED_PROTOCOL'] === 'https'); ++ } elseif ( isset($_SERVER['HTTPS']) ++ && !empty($_SERVER['HTTPS']) ++ && strcasecmp($_SERVER['HTTPS'], 'off') !== 0 ++ ) { ++ return true; ++ } ++ return false; ++ } ++ ++ /** ++ * Remove standard HTTP and HTTPS port for discovery and allowlist input. ++ * ++ * @param $url URL as https://domain:port without trailing slash ++ * @return standardized URL, or the original URL ++ * @throws CAS_InvalidArgumentException if the URL does not include the protocol ++ */ ++ protected function removeStandardPort($url) { ++ if (strpos($url, "://") === false) { ++ throw new CAS_InvalidArgumentException( ++ "Configured base URL should include the protocol string: " . $url); ++ } ++ ++ $url = rtrim($url, '/'); ++ ++ if (strpos($url, "https://") === 0 && substr_compare($url, ':443', -4) === 0) { ++ return substr($url, 0, -4); ++ } ++ ++ if (strpos($url, "http://") === 0 && substr_compare($url, ':80', -3) === 0) { ++ return substr($url, 0, -3); ++ } ++ ++ return $url; ++ } ++ ++} +--- /dev/null ++++ b/source/CAS/ServiceBaseUrl/Interface.php +@@ -0,0 +1,61 @@ ++<?php ++ ++/** ++ * Licensed to Jasig under one or more contributor license ++ * agreements. See the NOTICE file distributed with this work for ++ * additional information regarding copyright ownership. ++ * ++ * Jasig licenses this file to you under the Apache License, ++ * Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * PHP Version 7 ++ * ++ * @file CAS/ServerHostname/Interface.php ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @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 gets the server name of the PHP server. ++ * This is used to generate service URL and PGT callback URL. ++ * ++ * @class CAS_ServiceBaseUrl_Interface ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++interface CAS_ServiceBaseUrl_Interface ++{ ++ ++ /** ++ * Get PHP HTTP protocol and server name. ++ * ++ * @return string protocol, server hostname, and optionally port, ++ * without trailing slash (https://localhost:8443) ++ */ ++ public function get(); ++ ++ /** ++ * Check whether HTTPS is used. ++ * ++ * This is used to construct the protocol in the URL. ++ * ++ * @return bool true if HTTPS is used ++ */ ++ public function isHttps(); ++ ++} +--- /dev/null ++++ b/source/CAS/ServiceBaseUrl/Static.php +@@ -0,0 +1,69 @@ ++<?php ++ ++/** ++ * Licensed to Jasig under one or more contributor license ++ * agreements. See the NOTICE file distributed with this work for ++ * additional information regarding copyright ownership. ++ * ++ * Jasig licenses this file to you under the Apache License, ++ * Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * PHP Version 7 ++ * ++ * @file CAS/ServiceBaseUrl/Static.php ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++ ++/** ++ * Class that gets the server name of the PHP server by statically set ++ * hostname and port. This is used to generate service URL and PGT ++ * callback URL. ++ * ++ * @class CAS_ServiceBaseUrl_Static ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++class CAS_ServiceBaseUrl_Static ++extends CAS_ServiceBaseUrl_Base ++{ ++ private $_name = null; ++ ++ public function __construct($name) { ++ if (is_string($name)) { ++ $this->_name = $this->removeStandardPort($name); ++ } else { ++ throw new CAS_TypeMismatchException($name, '$name', 'string'); ++ } ++ } ++ ++ /** ++ * Get the server name through static config. ++ * ++ * @return string the server hostname and port of the server configured ++ */ ++ public function get() ++ { ++ phpCAS::traceBegin(); ++ phpCAS::trace("Returning static server name: " . $this->_name); ++ phpCAS::traceEnd(true); ++ return $this->_name; ++ } ++} +\ No newline at end of file +--- /dev/null ++++ b/test/CAS/Tests/ServiceBaseUrlTest.php +@@ -0,0 +1,244 @@ ++<?php ++ ++/** ++ * Licensed to Jasig under one or more contributor license ++ * agreements. See the NOTICE file distributed with this work for ++ * additional information regarding copyright ownership. ++ * ++ * Jasig licenses this file to you under the Apache License, ++ * Version 2.0 (the "License"); you may not use this file except in ++ * compliance with the License. You may obtain a copy of the License at: ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ * ++ * PHP Version 7 ++ * ++ * @file CAS/Tests/ServiceBaseUrlTest.php ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++ ++namespace PhpCas\Tests; ++ ++use PHPUnit\Framework\TestCase; ++ ++/** ++ * Test class for verifying the operation of the ServiceBaseUrl classes. ++ * ++ * @class ServiceBaseUrlTest ++ * @category Authentication ++ * @package PhpCAS ++ * @author Henry Pan <g...@phy25.com> ++ * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 ++ * @link https://wiki.jasig.org/display/CASC/phpCAS ++ */ ++class ServiceBaseUrlTest extends TestCase ++{ ++ /** ++ * @var CAS_Client ++ */ ++ protected $object; ++ ++ const DEFAULT_NAME = 'https://default.domain'; ++ ++ const DOMAIN_1 = 'http://domain1'; ++ ++ /** ++ * Sets up the fixture, for example, opens a network connection. ++ * This method is called before a test is executed. ++ */ ++ protected function setUp(): void ++ { ++ $this->object = new \CAS_ServiceBaseUrl_AllowedListDiscovery(array(self::DEFAULT_NAME, self::DOMAIN_1)); ++ } ++ ++ /** ++ * Tears down the fixture, for example, closes a network connection. ++ * This method is called after a test is executed. ++ */ ++ protected function tearDown(): void ++ { ++ ++ } ++ ++ /********************************************************* ++ * Tests of public (interface) methods ++ *********************************************************/ ++ ++ /** ++ * Verify that non allowlisted SERVER_NAME will return default name. ++ * ++ * @return void ++ */ ++ public function testNonAllowlistedServerName() ++ { ++ $_SERVER['SERVER_NAME'] = 'domain1:8080'; ++ ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that non allowlisted HTTP_HOST will return default name. ++ * ++ * @return void ++ */ ++ public function testNonAllowlistedHttpHost() ++ { ++ $_SERVER['HTTP_HOST'] = 'domain1:8080'; ++ $_SERVER['SERVER_NAME'] = ''; ++ ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that non allowlisted HTTP_X_FORWARDED_SERVER will return default name. ++ * ++ * @return void ++ */ ++ public function testNonAllowlistedXForwardedServer() ++ { ++ $_SERVER['HTTP_X_FORWARDED_SERVER'] = 'domain1'; ++ $_SERVER['HTTP_X_FORWARDED_PORT'] = '8080'; ++ ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that non allowlisted HTTP_X_FORWARDED_SERVER will return. ++ * ++ * @return void ++ */ ++ public function testNonAllowlistedXForwardedHost() ++ { ++ $_SERVER['HTTP_X_FORWARDED_HOST'] = 'domain1:8080'; ++ ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted SERVER_NAME will return in standarized form. ++ * ++ * @return void ++ */ ++ public function testAllowlistedServerName() ++ { ++ $_SERVER['SERVER_NAME'] = 'domain1'; ++ $_SERVER['HTTP_X_FORWARDED_PORT'] = '80'; ++ ++ $this->assertSame(self::DOMAIN_1, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_HOST will return. ++ * ++ * @return void ++ */ ++ public function testAllowlistedHttpHost() ++ { ++ $_SERVER['HTTP_HOST'] = 'domain1'; ++ $_SERVER['SERVER_NAME'] = ''; ++ $_SERVER['HTTP_X_FORWARDED_PORT'] = '80'; ++ ++ $this->assertSame(self::DOMAIN_1, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_X_FORWARDED_SERVER will return. ++ * ++ * @return void ++ */ ++ public function testAllowlistedXForwardedServer() ++ { ++ $_SERVER['HTTP_X_FORWARDED_SERVER'] = 'domain1'; ++ $_SERVER['HTTP_X_FORWARDED_PORT'] = '80'; ++ ++ $this->assertSame(self::DOMAIN_1, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_X_FORWARDED_HOST will return. ++ * ++ * @return void ++ */ ++ public function testAllowlistedXForwardedHost() ++ { ++ $_SERVER['HTTP_X_FORWARDED_HOST'] = 'domain1'; ++ ++ $this->assertSame(self::DOMAIN_1, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_X_FORWARDED_HOST will return with a HTTP allowlist ++ * that needs to be standardized. ++ * ++ * @return void ++ */ ++ public function testAllowlistedXForwardedHostHttpStandardized() ++ { ++ $_SERVER['HTTP_X_FORWARDED_HOST'] = 'domain1'; ++ ++ $this->object = new \CAS_ServiceBaseUrl_AllowedListDiscovery(array(self::DEFAULT_NAME, "http://domain1:80/")); ++ $this->assertSame(self::DOMAIN_1, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_X_FORWARDED_HOST will return with a HTTP allowlist ++ * that needs to be standardized. ++ * ++ * @return void ++ */ ++ public function testAllowlistedXForwardedHostWithSslHttpsStandardized() ++ { ++ $_SERVER['HTTPS'] = 'on'; ++ $_SERVER['HTTP_X_FORWARDED_HOST'] = 'default.domain:443'; ++ ++ $this->object = new \CAS_ServiceBaseUrl_AllowedListDiscovery(array("https://default.domain:443/", self::DOMAIN_1)); ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that allowlisted HTTP_X_FORWARDED_HOST will return with a HTTP allowlist ++ * that needs to be standardized. ++ * ++ * @return void ++ */ ++ public function testAllowlistedXForwardedHostHttpsStandardized() ++ { ++ $_SERVER['HTTP_X_FORWARDED_HOST'] = 'default.domain:443'; ++ ++ $this->object = new \CAS_ServiceBaseUrl_AllowedListDiscovery(array("https://default.domain:443/", "http://default.domain:443/")); ++ $this->assertSame("http://default.domain:443", $this->object->get()); ++ } ++ ++ /** ++ * Verify that static configuration always return the standardized base URL. ++ * ++ * @return void ++ */ ++ public function testStaticHappyPath() ++ { ++ $this->object = new \CAS_ServiceBaseUrl_Static("https://default.domain:443/"); ++ $this->assertSame(self::DEFAULT_NAME, $this->object->get()); ++ } ++ ++ /** ++ * Verify that static configuration always return the standardized base URL. ++ * ++ * @return void ++ */ ++ public function testStaticNoProtocol() ++ { ++ $this->expectException(\CAS_InvalidArgumentException::class); ++ $this->object = new \CAS_ServiceBaseUrl_Static("default.domain/"); ++ } ++ ++} +--- a/source/CAS.php ++++ b/source/CAS.php +@@ -327,6 +327,14 @@ + * @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 string|string[]|CAS_ServiceBaseUrl_Interface ++ * $service_base_url the base URL (protocol, host and the ++ * optional port) of the CAS client; pass ++ * in an array to use auto discovery with ++ * an allowlist; pass in ++ * CAS_ServiceBaseUrl_Interface for custom ++ * behavior. Added in 1.6.0. Similar to ++ * serverName config in other CAS clients. + * @param bool $changeSessionID Allow phpCAS to change the session_id (Single + * Sign Out/handleLogoutRequests is based on that change) + * +@@ -336,7 +344,7 @@ + * and phpCAS::setDebug()). + */ + public static function client($server_version, $server_hostname, +- $server_port, $server_uri, $changeSessionID = true ++ $server_port, $server_uri, $service_base_url, $changeSessionID = true + ) { + phpCAS :: traceBegin(); + if (is_object(self::$_PHPCAS_CLIENT)) { +@@ -355,7 +363,7 @@ + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( +- $server_version, false, $server_hostname, $server_port, $server_uri, ++ $server_version, false, $server_hostname, $server_port, $server_uri, $service_base_url, + $changeSessionID + ); + } catch (Exception $e) { +@@ -371,6 +379,14 @@ + * @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 string|string[]|CAS_ServiceBaseUrl_Interface ++ * $service_base_url the base URL (protocol, host and the ++ * optional port) of the CAS client; pass ++ * in an array to use auto discovery with ++ * an allowlist; pass in ++ * CAS_ServiceBaseUrl_Interface for custom ++ * behavior. Added in 1.6.0. Similar to ++ * serverName config in other CAS clients. + * @param bool $changeSessionID Allow phpCAS to change the session_id (Single + * Sign Out/handleLogoutRequests is based on that change) + * +@@ -380,7 +396,7 @@ + * and phpCAS::setDebug()). + */ + public static function proxy($server_version, $server_hostname, +- $server_port, $server_uri, $changeSessionID = true ++ $server_port, $server_uri, $service_base_url, $changeSessionID = true + ) { + phpCAS :: traceBegin(); + if (is_object(self::$_PHPCAS_CLIENT)) { +@@ -399,7 +415,7 @@ + // initialize the object $_PHPCAS_CLIENT + try { + self::$_PHPCAS_CLIENT = new CAS_Client( +- $server_version, true, $server_hostname, $server_port, $server_uri, ++ $server_version, true, $server_hostname, $server_port, $server_uri, $service_base_url, + $changeSessionID + ); + } catch (Exception $e) { diff -Nru php-cas-1.3.6/debian/patches/series php-cas-1.3.6/debian/patches/series --- php-cas-1.3.6/debian/patches/series 1970-01-01 01:00:00.000000000 +0100 +++ php-cas-1.3.6/debian/patches/series 2023-06-19 17:12:56.000000000 +0200 @@ -0,0 +1 @@ +CVE-2022-39369.patch
signature.asc
Description: PGP signature