From 08f83153132b976dbc80f878c68085d6a76bcf31 Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Sat, 1 Jun 2024 15:35:57 +0200 Subject: [PATCH 1/5] Update the LDAP password validation because some servers will not include "userpassword" to the LDAP entries result (#1547) --- application/libraries/Ldap_client.php | 45 ++++----------------------- 1 file changed, 6 insertions(+), 39 deletions(-) diff --git a/application/libraries/Ldap_client.php b/application/libraries/Ldap_client.php index 9c55e642..1dd78cd6 100644 --- a/application/libraries/Ldap_client.php +++ b/application/libraries/Ldap_client.php @@ -97,52 +97,19 @@ class Ldap_client $user = $this->CI->accounts->get_user_by_username($username); if (empty($user['ldap_dn'])) { - return null; + return null; // User does not exist in Easy!Appointments } // Connect to LDAP server - $host = setting('ldap_host'); - $port = (int) setting('ldap_port'); - $user_dn = setting('ldap_user_dn'); - $ldap_password = setting('ldap_password'); + $ldap_host = setting('ldap_host'); + $ldap_port = (int) setting('ldap_port'); - $connection = @ldap_connect($host, $port); + $connection = @ldap_connect($ldap_host, $ldap_port); - if (!$connection) { - throw new Exception('Could not connect to LDAP server: ' . @ldap_error($connection)); - } - - @ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); - @ldap_set_option($connection, LDAP_OPT_REFERRALS, 0); // We need this for doing an LDAP search. - - $bind = @ldap_bind($connection, $user_dn, $ldap_password); - - if (!$bind) { - throw new Exception('LDAP bind failed: ' . @ldap_error($connection)); - } - - // Check the provided password against the LDAP service - - $filter = '(objectclass=*)'; - - $result = @ldap_search($connection, $user['ldap_dn'], $filter); - - if (!$result) { - return null; - } - - $ldap_entries = @ldap_get_entries($connection, $result); - - foreach ($ldap_entries as $ldap_entry) { - if (!is_array($ldap_entry) || empty($ldap_entry['dn']) || $ldap_entry['dn'] !== $user['ldap_dn']) { - continue; - } - - if (!$this->validate_password($password, $ldap_entry['userpassword'][0])) { - continue; - } + $user_bind = @ldap_bind($connection, $user['ldap_dn'], $password); + if ($user_bind) { $role = $this->CI->roles_model->find($user['id_roles']); $default_timezone = $this->CI->timezones->get_default_timezone(); From 3a488c223834d9427340b7559eee381afe9cbc9a Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Sat, 1 Jun 2024 15:47:12 +0200 Subject: [PATCH 2/5] Set protocol configuration before creating a new LDAP binding --- application/libraries/Ldap_client.php | 30 +-------------------------- 1 file changed, 1 insertion(+), 29 deletions(-) diff --git a/application/libraries/Ldap_client.php b/application/libraries/Ldap_client.php index 1dd78cd6..1095fc96 100644 --- a/application/libraries/Ldap_client.php +++ b/application/libraries/Ldap_client.php @@ -38,34 +38,6 @@ class Ldap_client $this->CI->load->library('accounts'); } - /** - * Validate the provided password with an LDAP hashed password. - * - * @param string $password - * @param string $hashed_password - * - * @return bool - */ - public function validate_password(string $password, string $hashed_password): bool - { - if (empty($hashed_password) || ($hashed_password[0] !== '{' && $password === $hashed_password)) { - return false; - } - - if (str_starts_with($hashed_password, '{MD5}')) { - $encrypted_password = '{MD5}' . base64_encode(md5($password, true)); - } elseif (str_starts_with($hashed_password, '{SHA1}')) { - $encrypted_password = '{SHA}' . base64_encode(sha1($password, true)); - } elseif (str_starts_with($hashed_password, '{SSHA}')) { - $salt = substr(base64_decode(substr($hashed_password, 6)), 20); - $encrypted_password = '{SSHA}' . base64_encode(sha1($password . $salt, true) . $salt); - } else { - throw new RuntimeException('Unsupported password hash format'); - } - - return $hashed_password === $encrypted_password; - } - /** * Try authenticating the user with LDAP * @@ -106,7 +78,7 @@ class Ldap_client $ldap_port = (int) setting('ldap_port'); $connection = @ldap_connect($ldap_host, $ldap_port); - + @ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); $user_bind = @ldap_bind($connection, $user['ldap_dn'], $password); if ($user_bind) { From 29bf31ba0429fa28236d7e7516e6dbebacea35cc Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Sat, 1 Jun 2024 15:58:52 +0200 Subject: [PATCH 3/5] Create new "pure_html" helper function that uses the HTML purifier library to clean up HTML --- application/helpers/html_helper.php | 18 ++++++++ composer.json | 3 +- composer.lock | 65 ++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/application/helpers/html_helper.php b/application/helpers/html_helper.php index c3edcf3a..785518ec 100644 --- a/application/helpers/html_helper.php +++ b/application/helpers/html_helper.php @@ -178,3 +178,21 @@ if (!function_exists('slot')) { } } } + +if (!function_exists('pure_html')) { + /** + * Use this function in order to render HTML that comes from a text editor or similar, but strip the JS from it. + * + * @param string $markup + * + * @return string + */ + function pure_html(string $markup): string + { + $config = HTMLPurifier_Config::createDefault(); + + $purifier = new HTMLPurifier($config); + + return $purifier->purify($markup); + } +} diff --git a/composer.json b/composer.json index f175ec06..2be97738 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,8 @@ "monolog/monolog": "^2.8.0", "google/apiclient": "^2.12.6", "guzzlehttp/guzzle": "^7.5.0", - "sabre/vobject": "^4.5" + "sabre/vobject": "^4.5", + "ezyang/htmlpurifier": "^4.17" }, "require-dev": { "roave/security-advisories": "dev-master", diff --git a/composer.lock b/composer.lock index 1c5ab47d..508b4c85 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,69 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "42334bbe254b633b82b51280317f82a9", + "content-hash": "f9e5d7652965f4a744ffe0112e9e419c", "packages": [ + { + "name": "ezyang/htmlpurifier", + "version": "v4.17.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "reference": "bbc513d79acf6691fa9cf10f192c90dd2957f18c", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.17.0" + }, + "time": "2023-11-17T15:01:25+00:00" + }, { "name": "firebase/php-jwt", "version": "v6.10.0", @@ -4215,7 +4276,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.0", + "php": ">=8.1", "ext-curl": "*", "ext-json": "*", "ext-mbstring": "*", From 341c79085cc96734c3f9a771df0095cb07710206 Mon Sep 17 00:00:00 2001 From: Alex Tselegidis Date: Sat, 1 Jun 2024 15:59:19 +0200 Subject: [PATCH 4/5] Apply the new "pure_html" helper to the content that originates from the Legal Contents text editors (#1463) --- application/views/components/cookie_notice_modal.php | 2 +- application/views/components/privacy_policy_modal.php | 5 ++--- application/views/components/terms_and_conditions_modal.php | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/application/views/components/cookie_notice_modal.php b/application/views/components/cookie_notice_modal.php index 9d3312aa..40c51d51 100644 --- a/application/views/components/cookie_notice_modal.php +++ b/application/views/components/cookie_notice_modal.php @@ -13,7 +13,7 @@