1
0
Fork 0
mirror of https://github.com/Kozea/Radicale.git synced 2025-06-26 16:45:52 +00:00
This commit is contained in:
Dipl Ing. Péter Varkoly 2025-06-23 06:49:43 +02:00 committed by GitHub
commit ee3f1f4f7a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 95 additions and 31 deletions

15
config
View file

@ -93,15 +93,24 @@
# Path of the file containing password of the reader DN
#ldap_secret_file = /run/secrets/ldap_password
# the attribute to read the group memberships from in the user's LDAP entry (default: not set)
#ldap_groups_attribute = memberOf
# The filter to find the DN of the user. This filter must contain a python-style placeholder for the login
#ldap_filter = (&(objectClass=person)(uid={0}))
# the attribute holding the value to be used as username after authentication
#ldap_user_attribute = cn
# The attribute in user entry to read the group memberships from.
#ldap_groups_attribute =
# The attribute in group entries to read the group members from.
#ldap_group_members_attribute =
# The base dn to find the groups. Necessary only if ldap_group_members_attribute is defined and different from ldap_base.
#ldap_groups_base =
# Additional filter to find the groups when ldap_group_members_attribute is defined. The following filter will be built (&{ldap_groups_filter}({ldap_group_members_attribute}={user_dn})
#ldap_groups_filter =
# Use ssl on the ldap connection
# Soon to be deprecated, use ldap_security instead
#ldap_use_ssl = False

View file

@ -18,13 +18,14 @@
Authentication backend that checks credentials with a LDAP server.
Following parameters are needed in the configuration:
ldap_uri The LDAP URL to the server like ldap://localhost
ldap_base The baseDN of the LDAP server
ldap_base The baseDN of the LDAP server searching for users.
ldap_reader_dn The DN of a LDAP user with read access to get the user accounts
ldap_secret The password of the ldap_reader_dn
ldap_secret_file The path of the file containing the password of the ldap_reader_dn
ldap_filter The search filter to find the user to authenticate by the username
ldap_user_attribute The attribute to be used as username after authentication
ldap_groups_attribute The attribute containing group memberships in the LDAP user entry
ldap_groups_base The baseDN of the LDAP server searching for groups.
Following parameters controls SSL connections:
ldap_use_ssl If ssl encryption should be used (to be deprecated)
ldap_security The encryption mode to be used: *none*|tls|starttls
@ -47,6 +48,9 @@ class Auth(auth.BaseAuth):
_ldap_attributes: list[str] = []
_ldap_user_attr: str
_ldap_groups_attr: str
_ldap_group_members_attr: str
_ldap_groups_base: str
_ldap_groups_filter: str
_ldap_module_version: int = 3
_ldap_use_ssl: bool = False
_ldap_security: str = "none"
@ -78,6 +82,11 @@ class Auth(auth.BaseAuth):
self._ldap_filter = configuration.get("auth", "ldap_filter")
self._ldap_user_attr = configuration.get("auth", "ldap_user_attribute")
self._ldap_groups_attr = configuration.get("auth", "ldap_groups_attribute")
self._ldap_group_members_attr = configuration.get("auth", "ldap_group_members_attribute")
self._ldap_groups_base = configuration.get("auth", "ldap_groups_base")
if self._ldap_groups_base == "":
self._ldap_groups_base = self._ldap_base
self._ldap_groups_filter = configuration.get("auth", "ldap_groups_filter")
ldap_secret_file_path = configuration.get("auth", "ldap_secret_file")
if ldap_secret_file_path:
with open(ldap_secret_file_path, 'r') as file:
@ -102,6 +111,7 @@ class Auth(auth.BaseAuth):
logger.info("auth.ldap_base : %r" % self._ldap_base)
logger.info("auth.ldap_reader_dn : %r" % self._ldap_reader_dn)
logger.info("auth.ldap_filter : %r" % self._ldap_filter)
logger.info("auth.ldap_groups_base : %r" % self._ldap_groups_base)
if self._ldap_user_attr:
logger.info("auth.ldap_user_attribute : %r" % self._ldap_user_attr)
else:
@ -110,6 +120,14 @@ class Auth(auth.BaseAuth):
logger.info("auth.ldap_groups_attribute: %r" % self._ldap_groups_attr)
else:
logger.info("auth.ldap_groups_attribute: (not provided)")
if self._ldap_group_members_attr:
logger.info("auth.ldap_group_members_attr: %r" % self._ldap_group_members_attr)
else:
logger.info("auth.ldap_group_members_attr: (not provided)")
if self._ldap_groups_filter:
logger.info("auth.ldap_groups_filter: %r" % self._ldap_groups_filter)
else:
logger.info("auth.ldap_groups_filter: (not provided)")
if ldap_secret_file_path:
logger.info("auth.ldap_secret_file_path: %r" % ldap_secret_file_path)
if self._ldap_secret:
@ -172,17 +190,28 @@ class Auth(auth.BaseAuth):
conn.set_option(self.ldap.OPT_REFERRALS, 0)
conn.simple_bind_s(user_dn, password)
tmp: list[str] = []
gdns: list[str] = []
if self._ldap_groups_attr:
tmp = []
for g in user_entry[1][self._ldap_groups_attr]:
"""Get group g's RDN's attribute value"""
try:
rdns = self.ldap.dn.explode_dn(g, notypes=True)
tmp.append(rdns[0])
except Exception:
tmp.append(g.decode('utf8'))
self._ldap_groups = set(tmp)
logger.debug("_login2 LDAP groups of user: %s", ",".join(self._ldap_groups))
gdns = user_entry[1][self._ldap_groups_attr]
elif self._ldap_group_members_attr:
res = conn.search_s(
self._ldap_groups_base,
self.ldap.SCOPE_SUBTREE,
filterstr="(&{0}({1}={2}))".format(
self._ldap_groups_filter,
self._ldap_group_members_attr,
self.ldap.filter.escape_filter_chars(user_dn)),
attrlist=self._ldap_attributes
)
for g in gdns:
"""Get group g's RDN's attribute value"""
try:
rdns = self.ldap.dn.explode_dn(g, notypes=True)
tmp.append(rdns[0])
except Exception:
tmp.append(g.decode('utf8'))
self._ldap_groups = set(tmp)
logger.debug("_login2 LDAP groups of user: %s", ",".join(self._ldap_groups))
if self._ldap_user_attr:
if user_entry[1][self._ldap_user_attr]:
tmplogin = user_entry[1][self._ldap_user_attr][0]
@ -261,17 +290,31 @@ class Auth(auth.BaseAuth):
logger.debug(f"_login3 user '{login}' cannot be found")
return ""
tmp: list[str] = []
gdns: list[str] = []
"""Let's collect the groups of the user."""
if self._ldap_groups_attr:
tmp = []
for g in user_entry['attributes'][self._ldap_groups_attr]:
"""Get group g's RDN's attribute value"""
try:
rdns = self.ldap3.utils.dn.parse_dn(g)
tmp.append(rdns[0][1])
except Exception:
tmp.append(g)
self._ldap_groups = set(tmp)
logger.debug("_login3 LDAP groups of user: %s", ",".join(self._ldap_groups))
gdns = user_entry['attributes'][self._ldap_groups_attr]
elif self._ldap_group_members_attr:
conn.search(
search_base=self._ldap_groups_base,
search_filter="(&{0}({1}={2}))".format(
self._ldap_groups_filter,
self._ldap_group_members_attr,
self.ldap3.utils.conv.escape_filter_chars(user_dn)),
search_scope=self.ldap3.SUBTREE,
attributes="dn"
)
for group in conn.response:
gdns.append(group['dn'])
for g in gdns:
"""Get group g's RDN's attribute value"""
try:
rdns = self.ldap3.utils.dn.parse_dn(g)
tmp.append(rdns[0][1])
except Exception:
tmp.append(g)
self._ldap_groups = set(tmp)
logger.debug("_login3 LDAP groups of user: %s", ",".join(self._ldap_groups))
if self._ldap_user_attr:
if user_entry['attributes'][self._ldap_user_attr]:
if isinstance(user_entry['attributes'][self._ldap_user_attr], list):

View file

@ -269,31 +269,43 @@ DEFAULT_CONFIG_SCHEMA: types.CONFIG_SCHEMA = OrderedDict([
"type": str}),
("ldap_base", {
"value": "",
"help": "LDAP base DN of the ldap server",
"help": "The base DN of the ldap server where the user can be find.",
"type": str}),
("ldap_reader_dn", {
"value": "",
"help": "the DN of a ldap user with read access to get the user accounts",
"help": "The DN of a ldap user with read access to get the user accounts",
"type": str}),
("ldap_secret", {
"value": "",
"help": "the password of the ldap_reader_dn",
"help": "The password of the ldap_reader_dn",
"type": str}),
("ldap_secret_file", {
"value": "",
"help": "path of the file containing the password of the ldap_reader_dn",
"help": "Path of the file containing the password of the ldap_reader_dn",
"type": str}),
("ldap_filter", {
"value": "(cn={0})",
"help": "the search filter to find the user DN to authenticate by the username",
"help": "The search filter to find the user DN to authenticate by the username",
"type": str}),
("ldap_user_attribute", {
"value": "",
"help": "the attribute to be used as username after authentication",
"help": "The attribute to be used as username after authentication",
"type": str}),
("ldap_groups_attribute", {
"value": "",
"help": "attribute to read the group memberships from",
"help": "Attribute in the user entry to read the group memberships from.",
"type": str}),
("ldap_group_members_attribute", {
"value": "",
"help": "Attribute in the group entries to read the group members from.",
"type": str}),
("ldap_groups_base", {
"value": "",
"help": "The base dn to find the groups. Necessary only if ldap_group_members_attribute is defined and different from ldap_base.",
"type": str}),
("ldap_groups_filter", {
"value": "",
"help": "Additional filter to find the groups when ldap_group_members_attribute is defined. The following filter will be built (&{ldap_groups_filter}({ldap_group_members_attribute}={user_dn})",
"type": str}),
("ldap_use_ssl", {
"value": "False",