mirror of
https://github.com/mealie-recipes/mealie.git
synced 2026-02-07 08:23:12 -05:00
feat: LDAP Improvements and E2E testing (#2199)
* add option to enable starttls for ldap * add integration test for ldap service * document new, optional environment variable * fix: support anonymous bind * id and mail attributes in LDAP_USER_FILTER should be implied * remove print statement
This commit is contained in:
@@ -4,6 +4,7 @@ from pathlib import Path
|
||||
|
||||
from jose import jwt
|
||||
|
||||
from mealie.core import root_logger
|
||||
from mealie.core.config import get_app_settings
|
||||
from mealie.core.security.hasher import get_hasher
|
||||
from mealie.db.models.users.users import AuthMethod
|
||||
@@ -14,6 +15,8 @@ from mealie.services.user_services.user_service import UserService
|
||||
|
||||
ALGORITHM = "HS256"
|
||||
|
||||
logger = root_logger.get_logger("security")
|
||||
|
||||
|
||||
class UserLockedOut(Exception):
|
||||
...
|
||||
@@ -64,27 +67,52 @@ def user_from_ldap(db: AllRepositories, username: str, password: str) -> Private
|
||||
conn.set_option(ldap.OPT_X_TLS_CACERTFILE, settings.LDAP_TLS_CACERTFILE)
|
||||
conn.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
|
||||
|
||||
if settings.LDAP_ENABLE_STARTTLS:
|
||||
conn.start_tls_s()
|
||||
|
||||
# Use query user for the search instead of the logged in user
|
||||
# This prevents the need for every user to have query permissions in LDAP
|
||||
try:
|
||||
conn.simple_bind_s(settings.LDAP_QUERY_BIND, settings.LDAP_QUERY_PASSWORD)
|
||||
except (ldap.INVALID_CREDENTIALS, ldap.NO_SUCH_OBJECT):
|
||||
logger.error("[LDAP] Unable to bind to with provided user/password")
|
||||
return False
|
||||
|
||||
# Search "username" against "cn" attribute for Linux, "sAMAccountName" attribute
|
||||
# for Windows and "mail" attribute for email addresses. The "mail" attribute is
|
||||
# required to obtain the user's DN for the LDAP_ADMIN_FILTER.
|
||||
user_entry = conn.search_s(
|
||||
settings.LDAP_BASE_DN,
|
||||
ldap.SCOPE_SUBTREE,
|
||||
settings.LDAP_USER_FILTER.format(
|
||||
user_filter = ""
|
||||
if settings.LDAP_USER_FILTER:
|
||||
user_filter = settings.LDAP_USER_FILTER.format(
|
||||
id_attribute=settings.LDAP_ID_ATTRIBUTE, mail_attribute=settings.LDAP_MAIL_ATTRIBUTE, input=username
|
||||
),
|
||||
[settings.LDAP_ID_ATTRIBUTE, settings.LDAP_NAME_ATTRIBUTE, settings.LDAP_MAIL_ATTRIBUTE],
|
||||
)
|
||||
# Don't assume the provided search filter has (|({id_attribute}={input})({mail_attribute}={input}))
|
||||
search_filter = "(&(|({id_attribute}={input})({mail_attribute}={input})){filter})".format(
|
||||
id_attribute=settings.LDAP_ID_ATTRIBUTE,
|
||||
mail_attribute=settings.LDAP_MAIL_ATTRIBUTE,
|
||||
input=username,
|
||||
filter=user_filter,
|
||||
)
|
||||
|
||||
user_entry = None
|
||||
try:
|
||||
user_entry = conn.search_s(
|
||||
settings.LDAP_BASE_DN,
|
||||
ldap.SCOPE_SUBTREE,
|
||||
search_filter,
|
||||
[settings.LDAP_ID_ATTRIBUTE, settings.LDAP_NAME_ATTRIBUTE, settings.LDAP_MAIL_ATTRIBUTE],
|
||||
)
|
||||
except ldap.FILTER_ERROR:
|
||||
logger.error("[LDAP] Bad user search filter")
|
||||
|
||||
if not user_entry:
|
||||
conn.unbind_s()
|
||||
logger.error("[LDAP] No user was found with the provided user filter")
|
||||
return False
|
||||
|
||||
if len(user_entry) > 1:
|
||||
conn.unbind_s()
|
||||
logger.error("[LDAP] Multiple users found with the provided user filter")
|
||||
return False
|
||||
|
||||
user_dn, user_attr = user_entry[0]
|
||||
|
||||
@@ -130,6 +130,7 @@ class AppSettings(BaseSettings):
|
||||
LDAP_SERVER_URL: NoneStr = None
|
||||
LDAP_TLS_INSECURE: bool = False
|
||||
LDAP_TLS_CACERTFILE: NoneStr = None
|
||||
LDAP_ENABLE_STARTTLS: bool = False
|
||||
LDAP_BASE_DN: NoneStr = None
|
||||
LDAP_QUERY_BIND: NoneStr = None
|
||||
LDAP_QUERY_PASSWORD: NoneStr = None
|
||||
@@ -145,9 +146,6 @@ class AppSettings(BaseSettings):
|
||||
required = {
|
||||
self.LDAP_SERVER_URL,
|
||||
self.LDAP_BASE_DN,
|
||||
self.LDAP_USER_FILTER,
|
||||
self.LDAP_QUERY_BIND,
|
||||
self.LDAP_QUERY_PASSWORD,
|
||||
self.LDAP_ID_ATTRIBUTE,
|
||||
self.LDAP_MAIL_ATTRIBUTE,
|
||||
self.LDAP_NAME_ATTRIBUTE,
|
||||
|
||||
Reference in New Issue
Block a user