USER_FILTER is parsed with jinja

This commit is contained in:
Éloi Rivard 2023-07-04 18:34:16 +02:00
parent f19cc8a497
commit fd66f86a72
9 changed files with 38 additions and 23 deletions

View file

@ -3,11 +3,19 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_, The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_. and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
🚨Configuration files must be updated.🚨
Check the new format with ``git diff 0.0.29 0.0.30 canaille/conf/config.sample.toml``
Added Added
***** *****
- Configuration option to disable javascript :pr:`141` - Configuration option to disable javascript :pr:`141`
Changed
*******
- ``USER_FILTER`` is parsed with jinja.
[0.0.29] - 2023-06-30 [0.0.29] - 2023-06-30
===================== =====================
@ -28,7 +36,7 @@ Fixed
===================== =====================
🚨Configuration files must be updated.🚨 🚨Configuration files must be updated.🚨
Check the new format with ``git diff 0.0.27 0.0.26 canaille/conf/config.sample.toml`` Check the new format with ``git diff 0.0.26 0.0.27 canaille/conf/config.sample.toml``
Added Added
***** *****

View file

@ -219,13 +219,13 @@ class Backend(BaseBackend):
) )
placeholders = [] placeholders = []
if "cn={login}" in user_filter: if "cn={{login" in user_filter.replace(" ", ""):
placeholders.append(_("John Doe")) placeholders.append(_("John Doe"))
if "uid={login}" in user_filter: if "uid={{login" in user_filter.replace(" ", ""):
placeholders.append(_("jdoe")) placeholders.append(_("jdoe"))
if "mail={login}" in user_filter or not placeholders: if "mail={{login" in user_filter.replace(" ", "") or not placeholders:
placeholders.append(_("john@doe.com")) placeholders.append(_("john@doe.com"))
return _(" or ").join(placeholders) return _(" or ").join(placeholders)

View file

@ -44,11 +44,14 @@ class User(canaille.core.models.User, LDAPObject):
@classmethod @classmethod
def get_from_login(cls, login=None, **kwargs): def get_from_login(cls, login=None, **kwargs):
raw_filter = current_app.config["BACKENDS"]["LDAP"].get(
"USER_FILTER", User.DEFAULT_FILTER
)
filter = ( filter = (
( (
current_app.config["BACKENDS"]["LDAP"] current_app.jinja_env.from_string(raw_filter).render(
.get("USER_FILTER", User.DEFAULT_FILTER) login=ldap.filter.escape_filter_chars(login)
.format(login=ldap.filter.escape_filter_chars(login)) )
) )
if login if login
else None else None

View file

@ -81,9 +81,10 @@ USER_BASE = "ou=users,dc=mydomain,dc=tld"
# The attribute to identify an object in the User dn. # The attribute to identify an object in the User dn.
# USER_RDN = "uid" # USER_RDN = "uid"
# Filter to match users on sign in. Supports a variable # Filter to match users on sign in. Jinja syntax is supported
# {login} that can be used to compare against several fields: # and a `login` variable is available containing the value
# USER_FILTER = "(|(uid={login})(mail={login}))" # passed in the login field.
# USER_FILTER = "(|(uid={{ login }})(mail={{ login }}))"
# Where to search for groups? # Where to search for groups?
GROUP_BASE = "ou=groups,dc=mydomain,dc=tld" GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"

View file

@ -82,9 +82,10 @@ USER_BASE = "ou=users,dc=mydomain,dc=tld"
# The attribute to identify an object in the User dn. # The attribute to identify an object in the User dn.
USER_RDN = "uid" USER_RDN = "uid"
# Filter to match users on sign in. Supports a variable # Filter to match users on sign in. Jinja syntax is supported
# {login} that can be used to compare against several fields: # and a `login` variable is available containing the value
# USER_FILTER = "(|(uid={login})(mail={login}))" # passed in the login field.
# USER_FILTER = "(|(uid={{ login }})(mail={{ login }}))"
# Where to search for groups? # Where to search for groups?
GROUP_BASE = "ou=groups,dc=mydomain,dc=tld" GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"

View file

@ -82,9 +82,10 @@ USER_BASE = "ou=users,dc=mydomain,dc=tld"
# The attribute to identify an object in the User dn. # The attribute to identify an object in the User dn.
# USER_RDN = "uid" # USER_RDN = "uid"
# Filter to match users on sign in. Supports a variable # Filter to match users on sign in. Jinja syntax is supported
# {login} that can be used to compare against several fields: # and a `login` variable is available containing the value
# USER_FILTER = "(|(uid={login})(mail={login}))" # passed in the login field.
# USER_FILTER = "(|(uid={{ login }})(mail={{ login }}))"
# Where to search for groups? # Where to search for groups?
GROUP_BASE = "ou=groups,dc=mydomain,dc=tld" GROUP_BASE = "ou=groups,dc=mydomain,dc=tld"

View file

@ -115,8 +115,9 @@ BACKENDS.LDAP
:USER_FILTER: :USER_FILTER:
*Optional.* The filter to match users on sign in. *Optional.* The filter to match users on sign in.
Supports a variable {login} that can be used to compare against several LDAP attributes. Jinja syntax is supported and a `login` variable is available containing
Defaults to ``(|(uid={login})(mail={login}))`` the value passed in the login field.
Defaults to ``(|(uid={{ login }})(mail={{ login }}))``
:GROUP_BASE: :GROUP_BASE:
**Required.** The DN where of the node in which LDAP groups will be created and searched for. **Required.** The DN where of the node in which LDAP groups will be created and searched for.

View file

@ -35,7 +35,7 @@ def ldap_configuration(configuration, slapd_server):
"BIND_PW": slapd_server.root_pw, "BIND_PW": slapd_server.root_pw,
"USER_BASE": "ou=users", "USER_BASE": "ou=users",
"USER_RDN": "uid", "USER_RDN": "uid",
"USER_FILTER": "(uid={login})", "USER_FILTER": "(uid={{ login }})",
"GROUP_BASE": "ou=groups", "GROUP_BASE": "ou=groups",
"TIMEOUT": 0.1, "TIMEOUT": 0.1,
}, },

View file

@ -280,20 +280,20 @@ def test_ldap_cannot_create_groups(testclient, configuration, backend):
def test_login_placeholder(testclient): def test_login_placeholder(testclient):
testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(uid={login})" testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(uid={{ login }})"
placeholder = testclient.get("/login").form["login"].attrs["placeholder"] placeholder = testclient.get("/login").form["login"].attrs["placeholder"]
assert placeholder == "jdoe" assert placeholder == "jdoe"
testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(cn={login})" testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(cn={{ login }})"
placeholder = testclient.get("/login").form["login"].attrs["placeholder"] placeholder = testclient.get("/login").form["login"].attrs["placeholder"]
assert placeholder == "John Doe" assert placeholder == "John Doe"
testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(mail={login})" testclient.app.config["BACKENDS"]["LDAP"]["USER_FILTER"] = "(mail={{ login }})"
placeholder = testclient.get("/login").form["login"].attrs["placeholder"] placeholder = testclient.get("/login").form["login"].attrs["placeholder"]
assert placeholder == "john@doe.com" assert placeholder == "john@doe.com"
testclient.app.config["BACKENDS"]["LDAP"][ testclient.app.config["BACKENDS"]["LDAP"][
"USER_FILTER" "USER_FILTER"
] = "(|(uid={login})(mail={login}))" ] = "(|(uid={{ login }})(mail={{ login }}))"
placeholder = testclient.get("/login").form["login"].attrs["placeholder"] placeholder = testclient.get("/login").form["login"].attrs["placeholder"]
assert placeholder == "jdoe or john@doe.com" assert placeholder == "jdoe or john@doe.com"