From 61516154d2da4818f85567440103646776957f67 Mon Sep 17 00:00:00 2001 From: Dennis Buchhorn Date: Tue, 5 Dec 2023 21:00:39 +0100 Subject: [PATCH] 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"])