diff --git a/CHANGELOG.md b/CHANGELOG.md index 80845b21..2689fea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * Improve: avoid automatically invalid cache on upgrade in case no change on cache structure * Improve: log important module versions on startup * Improve: auth.ldap config shown on startup, terminate in case no password is supplied for bind user +* Add: option [auth] uc_username for uppercase conversion (similar to existing lc_username) ## 3.3.1 diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 283dbb63..0d914911 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -923,6 +923,17 @@ providers like ldap, kerberos Default: `False` +Note: cannot be enabled together with `uc_username` + +##### uc_username + +Сonvert username to uppercase, must be true for case-insensitive auth +providers like ldap, kerberos + +Default: `False` + +Note: cannot be enabled together with `lc_username` + ##### strip_domain Strip domain from username diff --git a/radicale/auth/__init__.py b/radicale/auth/__init__.py index 256ebe9e..566b9965 100644 --- a/radicale/auth/__init__.py +++ b/radicale/auth/__init__.py @@ -55,6 +55,7 @@ class BaseAuth: _ldap_groups: Set[str] = set([]) _lc_username: bool + _uc_username: bool _strip_domain: bool def __init__(self, configuration: "config.Configuration") -> None: @@ -67,7 +68,13 @@ class BaseAuth: """ self.configuration = configuration self._lc_username = configuration.get("auth", "lc_username") + self._uc_username = configuration.get("auth", "uc_username") self._strip_domain = configuration.get("auth", "strip_domain") + logger.info("auth.strip_domain: %s", self._strip_domain) + logger.info("auth.lc_username: %s", self._lc_username) + logger.info("auth.uc_username: %s", self._uc_username) + if self._lc_username is True and self._uc_username is True: + raise RuntimeError("auth.lc_username and auth.uc_username cannot be enabled together") def get_external_login(self, environ: types.WSGIEnviron) -> Union[ Tuple[()], Tuple[str, str]]: @@ -98,6 +105,8 @@ class BaseAuth: def login(self, login: str, password: str) -> str: if self._lc_username: login = login.lower() + if self._uc_username: + login = login.upper() if self._strip_domain: login = login.split('@')[0] return self._login(login, password) diff --git a/radicale/config.py b/radicale/config.py index d2af2ece..8ff1e14d 100644 --- a/radicale/config.py +++ b/radicale/config.py @@ -247,6 +247,10 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([ "value": "False", "help": "strip domain from username", "type": bool}), + ("uc_username", { + "value": "False", + "help": "convert username to uppercase, must be true for case-insensitive auth providers", + "type": bool}), ("lc_username", { "value": "False", "help": "convert username to lowercase, must be true for case-insensitive auth providers", diff --git a/radicale/tests/test_auth.py b/radicale/tests/test_auth.py index 5358e218..1142caf4 100644 --- a/radicale/tests/test_auth.py +++ b/radicale/tests/test_auth.py @@ -121,6 +121,11 @@ class TestBaseAuthRequests(BaseTest): self._test_htpasswd("plain", "tmp:bepo", ( ("tmp", "bepo", True), ("TMP", "bepo", True), ("tmp1", "bepo", False))) + def test_htpasswd_uc_username(self) -> None: + self.configure({"auth": {"uc_username": "True"}}) + self._test_htpasswd("plain", "TMP:bepo", ( + ("tmp", "bepo", True), ("TMP", "bepo", True), ("TMP1", "bepo", False))) + def test_htpasswd_strip_domain(self) -> None: self.configure({"auth": {"strip_domain": "True"}}) self._test_htpasswd("plain", "tmp:bepo", (