diff --git a/aleksis/core/settings.py b/aleksis/core/settings.py index 33d146e3f30f2d7fe0843c23f6f0cbc3a2d2aca4..ad5d7077eba8bccb0981f70b2ea7fffce7c9474c 100644 --- a/aleksis/core/settings.py +++ b/aleksis/core/settings.py @@ -209,6 +209,7 @@ if _settings.get("ldap.uri", None): import ldap # noqa from django_auth_ldap.config import ( LDAPSearch, + LDAPSearchUnion, NestedGroupOfNamesType, NestedGroupOfUniqueNamesType, PosixGroupType, @@ -224,27 +225,44 @@ if _settings.get("ldap.uri", None): AUTH_LDAP_BIND_DN = _settings.get("ldap.bind.dn") AUTH_LDAP_BIND_PASSWORD = _settings.get("ldap.bind.password") + # The TOML config might contain either one table or an array of tables + _AUTH_LDAP_USER_SETTINGS = _settings.get("ldap.users.search") + if not isinstance(_AUTH_LDAP_USER_SETTINGS, list): + _AUTH_LDAP_USER_SETTINGS = [_AUTH_LDAP_USER_SETTINGS] + # Search attributes to find users by username - AUTH_LDAP_USER_SEARCH = LDAPSearch( - _settings.get("ldap.users.base"), - ldap.SCOPE_SUBTREE, - _settings.get("ldap.users.filter", "(uid=%(user)s)"), + AUTH_LDAP_USER_SEARCH = LDAPSearchUnion( + *[ + LDAPSearch(entry["base"], ldap.SCOPE_SUBTREE, entry.get("filter", "(uid=%(user)s)"),) + for entry in _AUTH_LDAP_USER_SETTINGS + ] ) # Mapping of LDAP attributes to Django model fields AUTH_LDAP_USER_ATTR_MAP = { - "first_name": _settings.get("ldap.map.first_name", "givenName"), - "last_name": _settings.get("ldap.map.last_name", "sn"), - "email": _settings.get("ldap.map.email", "mail"), + "first_name": _settings.get("ldap.users.map.first_name", "givenName"), + "last_name": _settings.get("ldap.users.map.last_name", "sn"), + "email": _settings.get("ldap.users.map.email", "mail"), } # Discover flags by LDAP groups - if _settings.get("ldap.groups.base", None): + if _settings.get("ldap.groups.search", None): group_type = _settings.get("ldap.groups.type", "groupOfNames") - AUTH_LDAP_GROUP_SEARCH = LDAPSearch( - _settings.get("ldap.groups.base"), - ldap.SCOPE_SUBTREE, - _settings.get("ldap.groups.filter", f"(objectClass={group_type})"), + + # The TOML config might contain either one table or an array of tables + _AUTH_LDAP_GROUP_SETTINGS = _settings.get("ldap.groups.search") + if not isinstance(_AUTH_LDAP_GROUP_SETTINGS, list): + _AUTH_LDAP_GROUP_SETTINGS = [_AUTH_LDAP_GROUP_SETTINGS] + + AUTH_LDAP_GROUP_SEARCH = LDAPSearchUnion( + *[ + LDAPSearch( + entry["base"], + ldap.SCOPE_SUBTREE, + entry.get("filter", f"(objectClass={group_type})"), + ) + for entry in _AUTH_LDAP_GROUP_SETTINGS + ] ) _group_type = _settings.get("ldap.groups.type", "groupOfNames").lower() diff --git a/docs/admin/02_ldap.rst b/docs/admin/02_ldap.rst index e9c4745fcbf5767c6e6edc2c21f9b4ba0f64742e..1239d43e1b45d255100b249c417b44bd5de67b51 100644 --- a/docs/admin/02_ldap.rst +++ b/docs/admin/02_ldap.rst @@ -28,5 +28,7 @@ existing file or add a new one):: [default.ldap] uri = "ldaps://ldap.myschool.edu" bind = { dn = "cn=reader,dc=myschool,dc=edu", password = "secret" } - users = { base = "ou=people,dc=myschool,dc=edu", filter = "(uid=%(user)s)" } + + [default.ldap.users] + search = { base = "ou=people,dc=myschool,dc=edu", filter = "(uid=%(user)s)" } map = { first_name = "givenName", last_name = "sn", email = "mail" } diff --git a/poetry.lock b/poetry.lock index 45ff9dfd67e8640574c989cab86e52e93afe52f2..6b6e22ef2ddaa1765d78b32b42c7daf0a89f4e79 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2156,7 +2156,7 @@ celery = ["Celery", "django-celery-results", "django-celery-beat", "django-celer ldap = ["django-auth-ldap"] [metadata] -content-hash = "c6e41b0779be08ae7f643169504696ca0f6812408755a3acc9c1b0dc95752561" +content-hash = "e775ef8cb21bb2621d2088dfbd9cac6e1c165e6ffa50e17c40e8f769e322b1c8" python-versions = "^3.7" [metadata.files] @@ -2577,12 +2577,14 @@ kombu = [ {file = "kombu-4.6.11.tar.gz", hash = "sha256:ca1b45faac8c0b18493d02a8571792f3c40291cf2bcf1f55afed3d8f3aa7ba74"}, ] libsass = [ + {file = "libsass-0.20.0-cp27-cp27m-macosx_10_14_intel.whl", hash = "sha256:107c409524c6a4ed14410fa9dafa9ee59c6bd3ecae75d73af749ab2b75685726"}, {file = "libsass-0.20.0-cp27-cp27m-win32.whl", hash = "sha256:98f6dee9850b29e62977a963e3beb3cfeb98b128a267d59d2c3d675e298c8d57"}, {file = "libsass-0.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:b077261a04ba1c213e932943208471972c5230222acb7fa97373e55a40872cbb"}, {file = "libsass-0.20.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:e6a547c0aa731dcb4ed71f198e814bee0400ce04d553f3f12a53bc3a17f2a481"}, {file = "libsass-0.20.0-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:74f6fb8da58179b5d86586bc045c16d93d55074bc7bb48b6354a4da7ac9f9dfd"}, {file = "libsass-0.20.0-cp36-cp36m-win32.whl", hash = "sha256:a43f3830d83ad9a7f5013c05ce239ca71744d0780dad906587302ac5257bce60"}, {file = "libsass-0.20.0-cp36-cp36m-win_amd64.whl", hash = "sha256:fd19c8f73f70ffc6cbcca8139da08ea9a71fc48e7dfc4bb236ad88ab2d6558f1"}, + {file = "libsass-0.20.0-cp37-abi3-macosx_10_14_x86_64.whl", hash = "sha256:8cf72552b39e78a1852132e16b706406bc76029fe3001583284ece8d8752a60a"}, {file = "libsass-0.20.0-cp37-cp37m-win32.whl", hash = "sha256:7555d9b24e79943cfafac44dbb4ca7e62105c038de7c6b999838c9ff7b88645d"}, {file = "libsass-0.20.0-cp37-cp37m-win_amd64.whl", hash = "sha256:794f4f4661667263e7feafe5cc866e3746c7c8a9192b2aa9afffdadcbc91c687"}, {file = "libsass-0.20.0-cp38-cp38-win32.whl", hash = "sha256:3bc0d68778b30b5fa83199e18795314f64b26ca5871e026343e63934f616f7f7"}, diff --git a/pyproject.toml b/pyproject.toml index 62c12008070434590ad996dba60104d3dbc13373..07cacfc62d4b4cfd12475b83930725d11a21e6ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,7 +43,7 @@ libsass = "^0.20.0" colour = "^0.1.5" dynaconf = {version = "^2.0", extras = ["yaml", "toml", "ini"]} django-settings-context-processor = "^0.2" -django-auth-ldap = { version = "^2.0", optional = true } +django-auth-ldap = { version = "^2.2", optional = true } django-maintenance-mode = "^0.14.0" django-ipware = "^2.1" easy-thumbnails = "^2.6"