From 61516154d2da4818f85567440103646776957f67 Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Tue, 5 Dec 2023 21:00:39 +0100 Subject: [PATCH 1/7] feat[-multiple-]: create first version --- radicale-auth-ldap/__init__.py | 131 +++++++++++++++++++++++++++++++++ setup.py | 11 +++ 2 files changed, 142 insertions(+) create mode 100644 radicale-auth-ldap/__init__.py create mode 100755 setup.py diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py new file mode 100644 index 0000000..bc393fd --- /dev/null +++ b/radicale-auth-ldap/__init__.py @@ -0,0 +1,131 @@ +from radicale.auth import BaseAuth +from radicale.log import logger + +import ldap3 + +PLUGIN_CONFIG_SCHEMA = {"auth": { + "ldap_server_url": { + "value": None, + "type": str}, + "ldap_binddn": { + "value": None, + "type": str}, + "ldap_secret": { + "value": None, + "type": str}, + "ldap_search_base": { + "value": None, + "type": str}, + "ldap_user_filter": { + "value": None, + "type": str}, + "ldap_user_attribute": { + "value": None, + "type": str}, + "ldap_access_group_filter": { + "value": None, + "type": str}, + "ldap_access_group_attribute": { + "value": None, + "type": str}}} + +class Auth(BaseAuth): + def __init__(self, configuration): + super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA)) + + def login(self, user, password): + """Check if ``user``/``password`` couple is valid.""" + serverUrl = self.configuration.get("auth", "ldap_server_url") + binddn = self.configuration.get("auth", "ldap_binddn") + secret = self.configuration.get("auth", "ldap_secret") + searchBase = self.configuration.get("auth", "ldap_search_base") + userFilter = self.configuration.get("auth", "ldap_user_filter") + userAttribute = self.configuration.get("auth", "ldap_user_attribute") + accessGroupFilter = self.configuration.get("auth", "ldap_access_group_filter") + accessGroupAttribute = self.configuration.get("auth", "ldap_access_group_attribute") + + logger.debug("LDAP: start connection") + ## TODO: check for errors + server = ldap3.Server(serverUrl) + conn = ldap3.Connection(server, binddn, secret) + conn.bind() + result = conn.result + + logger.debug("LDAP bind result: %s" % str(result)) + + if result['description'] == "invalidCredentials": + return "" + + if accessGroupFilter: + logger.debug("LDAP access group filter: %s" % accessGroupFilter) + logger.debug("LDAP access group attribute: %s" % accessGroupAttribute) + + logger.debug("LDAP: search access group") + conn.search(searchBase, accessGroupFilter) + numberOfResponseEntries = len(conn.response) + + # ~ logger.debug("LDAP:") + logger.debug("LDAP search result: %s" % str(conn.result)) + logger.debug("LDAP number of response entries: %s" % str(numberOfResponseEntries)) + + if numberOfResponseEntries > 0: + if numberOfResponseEntries == 1: + accessGroupDn = conn.response[0]['dn'] + logger.debug("LDAP access group DN: %s" % accessGroupDn) + else: + logger.debug("LDAP: ERROR: more than 1 group found") + return "" + else: + logger.debug("LDAP: ERROR: no group found") + return "" + + logger.debug("LDAP user filter: %s" % userFilter) + logger.debug("LDAP user attribute: %s" % userAttribute) + + logger.debug("LDAP: search user %s" % user) + conn.search(searchBase, userFilter.format(name=user), attributes=[userAttribute, accessGroupAttribute]) + numberOfResponseEntries = len(conn.response) + + logger.debug("LDAP search result: %s" % str(conn.result)) + logger.debug("LDAP number of response entries: %s" % str(numberOfResponseEntries)) + + if numberOfResponseEntries > 0: + if numberOfResponseEntries == 1: + userDn = conn.response[0]['dn'] + userAttributeValue = conn.response[0]['attributes'][userAttribute] + logger.debug("LDAP user DN: %s" % userDn) + + if accessGroupFilter: + userMemberOf = conn.response[0]['attributes'][accessGroupAttribute] + + userIsInAccessGroup = False + for group in userMemberOf: + if group == accessGroupDn: + userIsInAccessGroup = True + break + + if userIsInAccessGroup: + logger.debug("LDAP: user is in access group") + else: + logger.debug("LDAP: user is NOT in access group") + return "" + else: + logger.debug("LDAP: ERROR: more than 1 user found") + return "" + else: + logger.debug("LDAP: ERROR: no user found") + return "" + + logger.debug("LDAP: restart connection for user") + ## TODO: check for errors + server = ldap3.Server(serverUrl) + conn = ldap3.Connection(server, userDn, password) + conn.bind() + result = conn.result + + logger.debug("LDAP bind result: %s" % str(result)) + + if result['description'] == "invalidCredentials": + return "" + else: + return userAttributeValue diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..6e411ba --- /dev/null +++ b/setup.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 + +from distutils.core import setup + +setup( + name="radicale-auth-ldap", + version="0.1", + description="LDAP Authentication Plugin for Radicale 3", + author="Dennis Buchhorn", + install_requires=["radicale >= 3.0", "ldap3 >= 2.3"], + packages=["radicale-auth-ldap"]) -- 2.26.2 From f2c0602e09ac52e20f12be88128168b4b210999a Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 20:45:17 +0100 Subject: [PATCH 2/7] feat[__init__.py]: add more logging --- radicale-auth-ldap/__init__.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index bc393fd..7a6ec96 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -44,16 +44,21 @@ class Auth(BaseAuth): accessGroupFilter = self.configuration.get("auth", "ldap_access_group_filter") accessGroupAttribute = self.configuration.get("auth", "ldap_access_group_attribute") - logger.debug("LDAP: start connection") + logger.info("LDAP: start connection") + logger.debug("LDAP: server URL: %s" % serverUrl) + logger.debug("LDAP: binddn: %s" % binddn) + logger.debug("LDAP: secret: %s" % secret) ## TODO: check for errors server = ldap3.Server(serverUrl) conn = ldap3.Connection(server, binddn, secret) conn.bind() result = conn.result + logger.info("LDAP: connection successful") logger.debug("LDAP bind result: %s" % str(result)) if result['description'] == "invalidCredentials": + logger.warning("LDAP: binddn credentials are invalid") return "" if accessGroupFilter: @@ -73,10 +78,10 @@ class Auth(BaseAuth): accessGroupDn = conn.response[0]['dn'] logger.debug("LDAP access group DN: %s" % accessGroupDn) else: - logger.debug("LDAP: ERROR: more than 1 group found") + logger.warning("LDAP: more than 1 group found") return "" else: - logger.debug("LDAP: ERROR: no group found") + logger.warning("LDAP: no group found") return "" logger.debug("LDAP user filter: %s" % userFilter) @@ -110,10 +115,10 @@ class Auth(BaseAuth): logger.debug("LDAP: user is NOT in access group") return "" else: - logger.debug("LDAP: ERROR: more than 1 user found") + logger.warning("LDAP: more than 1 user found") return "" else: - logger.debug("LDAP: ERROR: no user found") + logger.warning("LDAP: no user found") return "" logger.debug("LDAP: restart connection for user") @@ -126,6 +131,8 @@ class Auth(BaseAuth): logger.debug("LDAP bind result: %s" % str(result)) if result['description'] == "invalidCredentials": + logger.warning("LDAP: user credentials are invalid") return "" else: + logger.info("LDAP: user successful verified") return userAttributeValue -- 2.26.2 From 3c33627ead32d8c94f7f593a26f98df1465e7b7b Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 21:06:53 +0100 Subject: [PATCH 3/7] fix[__init__.py]: correct check if accessGroupFilter is not set --- radicale-auth-ldap/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index 7a6ec96..5065d9a 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -61,7 +61,7 @@ class Auth(BaseAuth): logger.warning("LDAP: binddn credentials are invalid") return "" - if accessGroupFilter: + if accessGroupFilter != None: logger.debug("LDAP access group filter: %s" % accessGroupFilter) logger.debug("LDAP access group attribute: %s" % accessGroupAttribute) @@ -100,7 +100,7 @@ class Auth(BaseAuth): userAttributeValue = conn.response[0]['attributes'][userAttribute] logger.debug("LDAP user DN: %s" % userDn) - if accessGroupFilter: + if accessGroupFilter != None: userMemberOf = conn.response[0]['attributes'][accessGroupAttribute] userIsInAccessGroup = False -- 2.26.2 From e3c66e7f37e3167b25454044cfc462a97e34c01c Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 21:13:52 +0100 Subject: [PATCH 4/7] fix[__init__.py]: correct check if accessGroupFilter and accessGroupAttribute is not set --- radicale-auth-ldap/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index 5065d9a..3705b1e 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -61,7 +61,7 @@ class Auth(BaseAuth): logger.warning("LDAP: binddn credentials are invalid") return "" - if accessGroupFilter != None: + if (not accessGroupFilter == None) and (not accessGroupAttribute == None): logger.debug("LDAP access group filter: %s" % accessGroupFilter) logger.debug("LDAP access group attribute: %s" % accessGroupAttribute) @@ -100,7 +100,7 @@ class Auth(BaseAuth): userAttributeValue = conn.response[0]['attributes'][userAttribute] logger.debug("LDAP user DN: %s" % userDn) - if accessGroupFilter != None: + if (not accessGroupFilter == None) and (not accessGroupAttribute == None): userMemberOf = conn.response[0]['attributes'][accessGroupAttribute] userIsInAccessGroup = False -- 2.26.2 From bfcf711e774cd8c1e0e991e037fcd80f571ec314 Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 21:21:09 +0100 Subject: [PATCH 5/7] fix[__init__.py]: correct check if accessGroupFilter and accessGroupAttribute is not set --- radicale-auth-ldap/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index 3705b1e..23e207f 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -23,10 +23,10 @@ PLUGIN_CONFIG_SCHEMA = {"auth": { "value": None, "type": str}, "ldap_access_group_filter": { - "value": None, + "value": "None", "type": str}, "ldap_access_group_attribute": { - "value": None, + "value": "None", "type": str}}} class Auth(BaseAuth): @@ -61,7 +61,7 @@ class Auth(BaseAuth): logger.warning("LDAP: binddn credentials are invalid") return "" - if (not accessGroupFilter == None) and (not accessGroupAttribute == None): + if (not accessGroupFilter == "None") and (not accessGroupAttribute == "None"): logger.debug("LDAP access group filter: %s" % accessGroupFilter) logger.debug("LDAP access group attribute: %s" % accessGroupAttribute) -- 2.26.2 From 62484e45d8f8bbbfc1bce4a2b8923ee89ae23f68 Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 21:25:13 +0100 Subject: [PATCH 6/7] fix[__init__.py]: correct ldap search when no accessGroupAttribute is set --- radicale-auth-ldap/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index 23e207f..c1e7597 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -88,7 +88,10 @@ class Auth(BaseAuth): logger.debug("LDAP user attribute: %s" % userAttribute) logger.debug("LDAP: search user %s" % user) - conn.search(searchBase, userFilter.format(name=user), attributes=[userAttribute, accessGroupAttribute]) + if (not accessGroupFilter == "None") and (not accessGroupAttribute == "None"): + conn.search(searchBase, userFilter.format(name=user), attributes=[userAttribute, accessGroupAttribute]) + else: + conn.search(searchBase, userFilter.format(name=user), attributes=[userAttribute]) numberOfResponseEntries = len(conn.response) logger.debug("LDAP search result: %s" % str(conn.result)) -- 2.26.2 From f9fbb8a0c796f629f6f30bf32a387bb2ae74171b Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Wed, 6 Dec 2023 21:29:48 +0100 Subject: [PATCH 7/7] fix[__init__.py]: correct check if accessGroupFilter and accessGroupAttribute is not set --- radicale-auth-ldap/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale-auth-ldap/__init__.py b/radicale-auth-ldap/__init__.py index c1e7597..beea2d0 100644 --- a/radicale-auth-ldap/__init__.py +++ b/radicale-auth-ldap/__init__.py @@ -103,7 +103,7 @@ class Auth(BaseAuth): userAttributeValue = conn.response[0]['attributes'][userAttribute] logger.debug("LDAP user DN: %s" % userDn) - if (not accessGroupFilter == None) and (not accessGroupAttribute == None): + if (not accessGroupFilter == "None") and (not accessGroupAttribute == "None"): userMemberOf = conn.response[0]['attributes'][accessGroupAttribute] userIsInAccessGroup = False -- 2.26.2