Update to support Radicale 3.x

master
Julien Dupouy 3 years ago
parent a396d8da41
commit 0e64ecc229

@ -1,5 +1,5 @@
# What is this?
This is an authentication plugin for Radicale 2. It adds an LDAP authentication backend which can be used for authenticating users against an LDAP server.
This is an authentication plugin for Radicale 3. It adds an LDAP authentication backend which can be used for authenticating users against an LDAP server.
# How to configure
You will need to set a few options inside your radicale config file. Example:

@ -30,12 +30,41 @@ import ldap3
import ldap3.core.exceptions
from radicale.auth import BaseAuth
from radicale.log import logger
import radicale_auth_ldap.ldap3imports
PLUGIN_CONFIG_SCHEMA = {"auth": {
"ldap_url": {
"value": "ldap://localhost:389",
"type": str},
"ldap_base": {
"value": "ou=Users",
"type": str},
"ldap_attribute": {
"value": "uid",
"type": str},
"ldap_filter": {
"value": "(objectClass=*)",
"type": str},
"ldap_binddn": {
"value": None,
"type": str},
"ldap_password": {
"value": None,
"type": str},
"ldap_scope": {
"value": "SUBTREE",
"type": str},
"ldap_support_extended": {
"value": True,
"type": bool}}}
class Auth(BaseAuth):
def is_authenticated(self, user, password):
def __init__(self, configuration):
super().__init__(configuration.copy(PLUGIN_CONFIG_SCHEMA))
def login(self, user, password):
"""Check if ``user``/``password`` couple is valid."""
SERVER = ldap3.Server(self.configuration.get("auth", "ldap_url"))
BASE = self.configuration.get("auth", "ldap_base")
@ -44,7 +73,7 @@ class Auth(BaseAuth):
BINDDN = self.configuration.get("auth", "ldap_binddn")
PASSWORD = self.configuration.get("auth", "ldap_password")
SCOPE = self.configuration.get("auth", "ldap_scope")
SUPPORT_EXTENDED = self.configuration.getboolean("auth", "ldap_support_extended", fallback=True)
SUPPORT_EXTENDED = self.configuration.get("auth", "ldap_support_extended")
if BINDDN and PASSWORD:
conn = ldap3.Connection(SERVER, BINDDN, PASSWORD)
@ -53,18 +82,18 @@ class Auth(BaseAuth):
conn.bind()
try:
self.logger.debug("LDAP whoami: %s" % conn.extend.standard.who_am_i())
logger.debug("LDAP whoami: %s" % conn.extend.standard.who_am_i())
except Exception as err:
self.logger.debug("LDAP error: %s" % err)
logger.debug("LDAP error: %s" % err)
distinguished_name = "%s=%s" % (ATTRIBUTE, ldap3imports.escape_attribute_value(user))
self.logger.debug("LDAP bind for %s in base %s" % (distinguished_name, BASE))
logger.debug("LDAP bind for %s in base %s" % (distinguished_name, BASE))
if FILTER:
filter_string = "(&(%s)%s)" % (distinguished_name, FILTER)
else:
filter_string = distinguished_name
self.logger.debug("LDAP filter: %s" % filter_string)
logger.debug("LDAP filter: %s" % filter_string)
conn.search(search_base=BASE,
search_scope=SCOPE,
@ -76,28 +105,28 @@ class Auth(BaseAuth):
if users:
user_dn = users[0]['dn']
uid = users[0]['attributes'][ATTRIBUTE]
self.logger.debug("LDAP user %s (%s) found" % (uid, user_dn))
logger.debug("LDAP user %s (%s) found" % (uid, user_dn))
try:
conn = ldap3.Connection(SERVER, user_dn, password)
conn.bind()
self.logger.debug(conn.result)
logger.debug(conn.result)
if SUPPORT_EXTENDED:
whoami = conn.extend.standard.who_am_i()
self.logger.debug("LDAP whoami: %s" % whoami)
logger.debug("LDAP whoami: %s" % whoami)
else:
self.logger.debug("LDAP skip extended: call whoami")
logger.debug("LDAP skip extended: call whoami")
whoami = conn.result['result'] == 0
if whoami:
self.logger.debug("LDAP bind OK")
return True
logger.debug("LDAP bind OK")
return uid[0]
else:
self.logger.debug("LDAP bind failed")
return False
logger.debug("LDAP bind failed")
return ""
except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
self.logger.debug("LDAP invalid credentials")
logger.debug("LDAP invalid credentials")
except Exception as err:
self.logger.debug("LDAP error %s" % err)
return False
logger.debug("LDAP error %s" % err)
return ""
else:
self.logger.debug("LDAP user %s not found" % user)
return False
logger.debug("LDAP user %s not found" % user)
return ""

@ -4,9 +4,9 @@ from setuptools import setup
setup(
name="radicale-auth-ldap",
version="0.1",
description="LDAP Authentication Plugin for Radicale 2",
version="3.0",
description="LDAP Authentication Plugin for Radicale 3",
author="Raoul Thill",
license="GNU GPL v3",
install_requires=["radicale >= 2.0", "ldap3 >= 2.3"],
install_requires=["radicale >= 3.0", "ldap3 >= 2.3"],
packages=["radicale_auth_ldap"])

@ -8,7 +8,8 @@ TEST_CONFIGURATION = {
'ldap_filter': '(objectClass=person)',
'ldap_binddn': 'cn=xxx,dc=xxx,dc=xx',
'ldap_password': '',
'ldap_scope': 'LEVEL'
'ldap_scope': 'LEVEL',
'ldap_support_extended': True
}
}

@ -10,16 +10,14 @@ from test.util import ConfigMock
class Authentication(unittest.TestCase):
configuration = None
logger = None
@classmethod
def setUpClass(cls):
cls.configuration = ConfigMock(TEST_CONFIGURATION)
cls.logger = logging.getLogger(__name__)
def test_authentication_works(self):
auth = radicale_auth_ldap.Auth(self.__class__.configuration, self.__class__.logger)
self.assertTrue(auth.is_authenticated(VALID_USER, VALID_PASS))
auth = radicale_auth_ldap.Auth(self.__class__.configuration)
self.assertTrue(auth.login(VALID_USER, VALID_PASS))
if __name__ == '__main__':

@ -11,3 +11,6 @@ class ConfigMock:
def get(self, a, b):
return self.configuration[a][b]
def copy(self, c):
return self

Loading…
Cancel
Save