diff --git a/htdocs/conf/conf.php.example b/htdocs/conf/conf.php.example index 3eef81ed5bb..f74c9e6b227 100644 --- a/htdocs/conf/conf.php.example +++ b/htdocs/conf/conf.php.example @@ -311,6 +311,18 @@ $dolibarr_main_force_https='0'; // $dolibarr_main_prod='1'; +// dolibarr_login_badcharunauthorized +// ================================== +// List of characters forbidden in Dolibarr user logins. +// This is a security-sensitive setting. Prefer LDAP/SSO mapping to the email field when possible. +// If this parameter is not defined, the secure default value is used: ,@<>"' +// Set it to an empty string only if you explicitly want to allow all characters. +// Set it to 'MAIN_LOGIN_BADCHARUNAUTHORIZED' only if you explicitly trust the Dolibarr hidden setup value. +// Examples: +// $dolibarr_login_badcharunauthorized=',@<>"\''; +// $dolibarr_login_badcharunauthorized=''; +// $dolibarr_login_badcharunauthorized='MAIN_LOGIN_BADCHARUNAUTHORIZED'; + // dolibarr_main_restrict_os_commands // ================================== // To restrict commands you can execute by the backup feature, enter allowed command here. diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 22e71595e5f..be6e8066b75 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -289,6 +289,26 @@ function getDolGlobalString($key, $default = '') return (string) (isset($conf->global->$key) ? $conf->global->$key : $default); } +/** + * Return the list of unauthorized characters in user logins. + * + * @return string + */ +function getDolGlobalLoginBadCharUnauthorized() +{ + global $dolibarr_login_badcharunauthorized; + + if (isset($dolibarr_login_badcharunauthorized)) { + if ($dolibarr_login_badcharunauthorized === 'MAIN_LOGIN_BADCHARUNAUTHORIZED') { + return getDolGlobalString('MAIN_LOGIN_BADCHARUNAUTHORIZED', ',@<>"\''); + } + + return (string) $dolibarr_login_badcharunauthorized; + } + + return ',@<>"\''; +} + /** * Return a Dolibarr global constant int value. * The constants $conf->global->xxx are loaded by the script master.inc.php included at begin of any PHP page. diff --git a/htdocs/core/lib/openid_connect.lib.php b/htdocs/core/lib/openid_connect.lib.php index be2ee215f3a..544a5b87438 100644 --- a/htdocs/core/lib/openid_connect.lib.php +++ b/htdocs/core/lib/openid_connect.lib.php @@ -122,11 +122,11 @@ function openid_connect_create_user($db, $userinfo, $login, $entity) $claim_firstname = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLAIM_FIRSTNAME', 'given_name'); $claim_lastname = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLAIM_LASTNAME', 'family_name'); - // Sanitize login: Dolibarr rejects certain characters (default: ,@<>"') - $badChars = getDolGlobalString('MAIN_LOGIN_BADCHARUNAUTHORIZED', ',@<>"\''); + // Sanitize login using Dolibarr forbidden characters for logins. + $badChars = getDolGlobalLoginBadCharUnauthorized(); $sanitized_login = $login; - if (preg_match('/['.preg_quote($badChars, '/').']/', $login)) { + if ($badChars !== '' && preg_match('/['.preg_quote($badChars, '/').']/', $login)) { // First try preferred_username from OIDC (common standard claim) if (property_exists($userinfo, 'preferred_username') && !empty($userinfo->preferred_username)) { $preferred = $userinfo->preferred_username; diff --git a/htdocs/user/class/user.class.php b/htdocs/user/class/user.class.php index 73410d46a16..3f7f9b38be9 100644 --- a/htdocs/user/class/user.class.php +++ b/htdocs/user/class/user.class.php @@ -1870,7 +1870,7 @@ class User extends CommonObject } dol_syslog(get_class($this)."::create login=".$this->login.", user=".(is_object($user) ? $user->id : ''), LOG_DEBUG); - $badCharUnauthorizedIntoLoginName = getDolGlobalString('MAIN_LOGIN_BADCHARUNAUTHORIZED', ',@<>"\''); + $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized(); // Check parameters if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) { @@ -1882,7 +1882,7 @@ class User extends CommonObject $langs->load("errors"); $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Login")); return -1; - } elseif (preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { + } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { $langs->load("errors"); $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login")); return -1; @@ -2282,7 +2282,7 @@ class User extends CommonObject $this->setUpperOrLowerCase(); // Check parameters - $badCharUnauthorizedIntoLoginName = getDolGlobalString('MAIN_LOGIN_BADCHARUNAUTHORIZED', ',@<>"\''); + $badCharUnauthorizedIntoLoginName = getDolGlobalLoginBadCharUnauthorized(); if (getDolGlobalString('USER_MAIL_REQUIRED') && !isValidEmail($this->email)) { $langs->load("errors"); @@ -2293,7 +2293,7 @@ class User extends CommonObject $langs->load("errors"); $this->error = $langs->trans("ErrorFieldRequired", 'Login'); return -1; - } elseif (preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { + } elseif ($badCharUnauthorizedIntoLoginName !== '' && preg_match('/['.preg_quote($badCharUnauthorizedIntoLoginName, '/').']/', $this->login)) { $langs->load("errors"); $this->error = $langs->trans("ErrorBadCharIntoLoginName", $langs->transnoentitiesnoconv("Login")); return -1;