From cec51a3d12f1f9db8accce1975d4c1405ecaaf65 Mon Sep 17 00:00:00 2001 From: Julian Rother <julianr@fsmpi.rwth-aachen.de> Date: Tue, 23 Feb 2021 23:40:37 +0100 Subject: [PATCH] Made all ldap parameters configurable --- deps/ldapalchemy | 2 +- uffd/default_config.cfg | 54 +++++++++++++++++++++++++--------------- uffd/mail/models.py | 16 ++++++------ uffd/user/models.py | 55 +++++++++++++++++++++++++---------------- 4 files changed, 77 insertions(+), 50 deletions(-) diff --git a/deps/ldapalchemy b/deps/ldapalchemy index d2c13338..2358086f 160000 --- a/deps/ldapalchemy +++ b/deps/ldapalchemy @@ -1 +1 @@ -Subproject commit d2c133381a8e536ee433e5ab305fc24146c0feb9 +Subproject commit 2358086f5b8184fe89bbb69334a5c80e9b20cfbf diff --git a/uffd/default_config.cfg b/uffd/default_config.cfg index b4c84145..91d665ff 100644 --- a/uffd/default_config.cfg +++ b/uffd/default_config.cfg @@ -1,35 +1,50 @@ -LDAP_BASE_USER="ou=users,dc=example,dc=com" -LDAP_BASE_GROUPS="ou=groups,dc=example,dc=com" -LDAP_BASE_MAIL="ou=postfix,dc=example,dc=com" +LDAP_USER_SEARCH_BASE="ou=users,dc=example,dc=com" +LDAP_USER_SEARCH_FILTER=[("objectClass", "person")] +LDAP_USER_OBJECTCLASSES=["top", "inetOrgPerson", "organizationalPerson", "person", "posixAccount"] +LDAP_USER_MIN_UID=10000 +LDAP_USER_MAX_UID=18999 +LDAP_USER_GID=20001 +LDAP_USER_DN_ATTRIBUTE="uid" +LDAP_USER_UID_ATTRIBUTE="uidNumber" +LDAP_USER_UID_ALIASES=[] +LDAP_USER_LOGINNAME_ATTRIBUTE="uid" +LDAP_USER_LOGINNAME_ALIASES=[] +LDAP_USER_DISPLAYNAME_ATTRIBUTE="cn" +LDAP_USER_DISPLAYNAME_ALIASES=["givenName", "displayName"] +LDAP_USER_MAIL_ATTRIBUTE="mail" +LDAP_USER_MAIL_ALIASES=[] +LDAP_USER_DEFAULT_ATTRIBUTES={ + "sn": " ", + "homeDirectory": "/home/{loginname}", + "gidNumber": LDAP_USER_GID +} -LDAP_FILTER_USER=[("objectClass","person")] -LDAP_FILTER_GROUP=[("objectClass","groupOfUniqueNames")] -LDAP_FILTER_MAIL=[("objectClass","postfixVirtual")] +LDAP_GROUP_SEARCH_BASE="ou=groups,dc=example,dc=com" +LDAP_GROUP_SEARCH_FILTER=[("objectClass","groupOfUniqueNames")] +LDAP_GROUP_GID_ATTRIBUTE="gidNumber" +LDAP_GROUP_NAME_ATTRIBUTE="cn" +LDAP_GROUP_DESCRIPTION_ATTRIBUTE="description" +LDAP_GROUP_MEMBER_ATTRIBUTE="uniqueMember" + +LDAP_MAIL_SEARCH_BASE="ou=postfix,dc=example,dc=com" +LDAP_MAIL_SEARCH_FILTER=[("objectClass","postfixVirtual")] +LDAP_MAIL_OBJECTCLASSES=["top", "postfixVirtual"] +LDAP_MAIL_DN_ATTRIBUTE="uid" +LDAP_MAIL_UID_ATTRIBUTE="uid" +LDAP_MAIL_RECEIVERS_ATTRIBUTE="mailacceptinggeneralid" +LDAP_MAIL_DESTINATIONS_ATTRIBUTE="maildrop" LDAP_SERVICE_BIND_DN="" LDAP_SERVICE_BIND_PASSWORD="" LDAP_SERVICE_URL="ldapi:///" LDAP_SERVICE_USE_STARTTLS=True -LDAP_USER_OBJECTCLASSES=["top", "inetOrgPerson", "organizationalPerson", "person", "posixAccount"] -LDAP_USER_ATTRIBUTE_UID="uidNumber" -LDAP_USER_ATTRIBUTE_DISPLAYNAME="cn" -LDAP_USER_ATTRIBUTE_MAIL="mail" -# The User class gets filled by which LDAP attribute and to type (single/list) -LDAP_USER_ATTRIBUTE_EXTRA={ -#"phone": {"type": "single", "name": "mobile"}, -} -LDAP_USER_GID=20001 -LDAP_USER_MIN_UID=10000 -LDAP_USER_MAX_UID=18999 - SESSION_LIFETIME_SECONDS=3600 # CSRF protection SESSION_COOKIE_SECURE=True SESSION_COOKIE_HTTPONLY=True SESSION_COOKIE_SAMESITE='Strict' - ACL_ADMIN_GROUP="uffd_admin" ACL_SELFSERVICE_GROUP="uffd_access" @@ -39,7 +54,6 @@ MAIL_USERNAME='yourId@example.com' MAIL_PASSWORD='*****' MAIL_USE_STARTTLS=True MAIL_FROM_ADDRESS='foo@bar.com' -MAIL_LDAP_OBJECTCLASSES=["top", "postfixVirtual"] #MFA_ICON_URL = 'https://example.com/logo.png' #MFA_RP_ID = 'example.com' # If unset, hostname from current request is used diff --git a/uffd/mail/models.py b/uffd/mail/models.py index 73f998c2..1791170a 100644 --- a/uffd/mail/models.py +++ b/uffd/mail/models.py @@ -2,12 +2,12 @@ from uffd.ldap import ldap from uffd.lazyconfig import lazyconfig_str, lazyconfig_list class Mail(ldap.Model): - ldap_search_base = lazyconfig_str('LDAP_BASE_MAIL') - ldap_filter_params = lazyconfig_list('LDAP_FILTER_MAIL') - ldap_object_classes = lazyconfig_list('MAIL_LDAP_OBJECTCLASSES') - ldap_dn_attribute = 'uid' - ldap_dn_base = lazyconfig_str('LDAP_BASE_MAIL') + ldap_search_base = lazyconfig_str('LDAP_MAIL_SEARCH_BASE') + ldap_filter_params = lazyconfig_list('LDAP_MAIL_SEARCH_FILTER') + ldap_object_classes = lazyconfig_list('LDAP_MAIL_OBJECTCLASSES') + ldap_dn_attribute = lazyconfig_str('LDAP_MAIL_DN_ATTRIBUTE') + ldap_dn_base = lazyconfig_str('LDAP_MAIL_SEARCH_BASE') - uid = ldap.Attribute('uid') - receivers = ldap.Attribute('mailacceptinggeneralid', multi=True) - destinations = ldap.Attribute('maildrop', multi=True) + uid = ldap.Attribute(lazyconfig_str('LDAP_MAIL_UID_ATTRIBUTE')) + receivers = ldap.Attribute(lazyconfig_str('LDAP_MAIL_RECEIVERS_ATTRIBUTE'), multi=True) + destinations = ldap.Attribute(lazyconfig_str('LDAP_MAIL_DESTINATIONS_ATTRIBUTE'), multi=True) diff --git a/uffd/user/models.py b/uffd/user/models.py index 7808a184..14435f00 100644 --- a/uffd/user/models.py +++ b/uffd/user/models.py @@ -17,29 +17,40 @@ def get_next_uid(): raise Exception('No free uid found') return next_uid -class User(ldap.Model): - ldap_search_base = lazyconfig_str('LDAP_BASE_USER') - ldap_filter_params = lazyconfig_list('LDAP_FILTER_USER') +class DictView: + def __init__(self, obj): + self.obj = obj + + def __getitem__(self, key): + return getattr(self.obj, key) + +class BaseUser(ldap.Model): + ldap_search_base = lazyconfig_str('LDAP_USER_SEARCH_BASE') + ldap_filter_params = lazyconfig_list('LDAP_USER_SEARCH_FILTER') ldap_object_classes = lazyconfig_list('LDAP_USER_OBJECTCLASSES') - ldap_dn_base = lazyconfig_str('LDAP_BASE_USER') - ldap_dn_attribute = 'uid' + ldap_dn_base = lazyconfig_str('LDAP_USER_SEARCH_BASE') + ldap_dn_attribute = lazyconfig_str('LDAP_USER_DN_ATTRIBUTE') - uid = ldap.Attribute(lazyconfig_str('LDAP_USER_ATTRIBUTE_UID'), default=get_next_uid) - loginname = ldap.Attribute('uid') - displayname = ldap.Attribute(lazyconfig_str('LDAP_USER_ATTRIBUTE_DISPLAYNAME'), aliases=['givenName', 'displayName']) - mail = ldap.Attribute(lazyconfig_str('LDAP_USER_ATTRIBUTE_MAIL')) + uid = ldap.Attribute(lazyconfig_str('LDAP_USER_UID_ATTRIBUTE'), default=get_next_uid, aliases=lazyconfig_list('LDAP_USER_UID_ALIASES')) + loginname = ldap.Attribute(lazyconfig_str('LDAP_USER_LOGINNAME_ATTRIBUTE'), aliases=lazyconfig_list('LDAP_USER_LOGINNAME_ALIASES')) + displayname = ldap.Attribute(lazyconfig_str('LDAP_USER_DISPLAYNAME_ATTRIBUTE'), aliases=lazyconfig_list('LDAP_USER_DISPLAYNAME_ALIASES')) + mail = ldap.Attribute(lazyconfig_str('LDAP_USER_MAIL_ATTRIBUTE'), aliases=lazyconfig_list('LDAP_USER_MAIL_ALIASES')) pwhash = ldap.Attribute('userPassword', default=lambda: hashed(HASHED_SALTED_SHA512, secrets.token_hex(128))) groups = [] # Shuts up pylint, overwritten by back-reference roles = [] # Shuts up pylint, overwritten by back-reference def dummy_attribute_defaults(self): - if self.ldap_object.getattr('sn') == []: - self.ldap_object.setattr('sn', [' ']) - if self.ldap_object.getattr('homeDirectory') == []: - self.ldap_object.setattr('homeDirectory', ['/home/%s'%self.loginname]) - if self.ldap_object.getattr('gidNumber') == []: - self.ldap_object.setattr('gidNumber', [current_app.config['LDAP_USER_GID']]) + for name, patterns in current_app.config['LDAP_USER_DEFAULT_ATTRIBUTES'].items(): + if not isinstance(patterns, list): + patterns = [patterns] + values = [] + for pattern in patterns: + if isinstance(pattern, str): + values.append(pattern.format_map(DictView(self))) + else: + values.append(pattern) + self.ldap_object.setattr(name, values) ldap_add_hooks = ldap.Model.ldap_add_hooks + (dummy_attribute_defaults,) @@ -101,13 +112,15 @@ class User(ldap.Model): self.mail = value return True +User = BaseUser + class Group(ldap.Model): - ldap_search_base = lazyconfig_str('LDAP_BASE_GROUPS') - ldap_filter_params = lazyconfig_list('LDAP_FILTER_GROUP') + ldap_search_base = lazyconfig_str('LDAP_GROUP_SEARCH_BASE') + ldap_filter_params = lazyconfig_list('LDAP_GROUP_SEARCH_FILTER') - gid = ldap.Attribute('gidNumber') - name = ldap.Attribute('cn') - description = ldap.Attribute('description', default='') - members = ldap.Relationship('uniqueMember', User, backref='groups') + gid = ldap.Attribute(lazyconfig_str('LDAP_GROUP_GID_ATTRIBUTE')) + name = ldap.Attribute(lazyconfig_str('LDAP_GROUP_NAME_ATTRIBUTE')) + description = ldap.Attribute(lazyconfig_str('LDAP_GROUP_DESCRIPTION_ATTRIBUTE'), default='') + members = ldap.Relationship(lazyconfig_str('LDAP_GROUP_MEMBER_ATTRIBUTE'), User, backref='groups') roles = [] # Shuts up pylint, overwritten by back-reference -- GitLab