diff --git a/docs/configuration.md b/docs/configuration.md index 41e4db5..f503d79 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -381,7 +381,16 @@ group_dn: CN=moonraker,OU=Groups,DC=ldap,DC=local # authentication. This option accepts Jinja2 Templates, see the [secrets] # section for details. The default is no group requirement. is_active_directory: True -# Enables support for Microsoft Active Directory. The default is False. +# Enables support for Microsoft Active Directory. This option changes the +# field used to lookup a user by username to sAMAccountName. +# The default is False. +user_filter: (&(objectClass=user)(cn=USERNAME)) +# Allows filter of users by custom LDAP query. Must contain the USERNAME +# token, it will be replaced by the user's username during lookup. Will +# override the change done by is_active_directory. This option accepts +# Jinja2 Templates, see the [secrets] section for details. +# The default is empty, which will change the lookup query depending on +# is_active_directory. ``` ### `[octoprint_compat]` diff --git a/moonraker/components/ldap.py b/moonraker/components/ldap.py index 77d72dc..18b4269 100644 --- a/moonraker/components/ldap.py +++ b/moonraker/components/ldap.py @@ -46,6 +46,15 @@ class MoonrakerLDAP: "required when 'bind_dn' is provided" ) self.bind_password = bind_pass_template.render() + self.user_filter: Optional[str] = None + user_filter_template = config.gettemplate('user_filter', None) + if user_filter_template is not None: + self.user_filter = user_filter_template.render() + if "USERNAME" not in self.user_filter: + raise config.error( + "Section [ldap]: Option 'user_filter' is " + "is missing required token USERNAME" + ) self.lock = asyncio.Lock() async def authenticate_ldap_user(self, username, password) -> None: @@ -67,6 +76,8 @@ class MoonrakerLDAP: } attr_name = "sAMAccountName" if self.active_directory else "uid" ldfilt = f"(&(objectClass=Person)({attr_name}={username}))" + if self.user_filter: + ldfilt = self.user_filter.replace("USERNAME", username) try: with ldap3.Connection(server, **conn_args) as conn: ret = conn.search(