diff --git a/uffd/ldap/__init__.py b/uffd/ldap/__init__.py
index 0ba10c72f766f8344737250c7584b151f949660f..436be193007b4c7543e633bbb1f3009d68a27046 100644
--- a/uffd/ldap/__init__.py
+++ b/uffd/ldap/__init__.py
@@ -1,4 +1,6 @@
 from .ldap import bp as ldap_bp
-from .ldap import get_conn, user_conn, escape_filter_chars, uid_to_dn, loginname_to_dn, get_next_uid, loginname_is_safe
+from .ldap import get_conn, user_conn, escape_filter_chars, uid_to_dn
+from .ldap import loginname_to_dn, get_next_uid, loginname_is_safe
+from .ldap import get_ldap_array_attribute_safe, get_ldap_attribute_safe
 
 bp = [ldap_bp]
diff --git a/uffd/ldap/ldap.py b/uffd/ldap/ldap.py
index 2d6d9c32f4c769e48bff5f77d42309e55da263fc..39fee2ff0d1eb97d497548419da17061f7461b3e 100644
--- a/uffd/ldap/ldap.py
+++ b/uffd/ldap/ldap.py
@@ -2,7 +2,7 @@ import string
 
 from flask import Blueprint, current_app
 from ldap3.utils.conv import escape_filter_chars
-from ldap3.core.exceptions import LDAPBindError
+from ldap3.core.exceptions import LDAPBindError, LDAPCursorError
 
 from ldap3 import Server, Connection, ALL, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES
 
@@ -42,8 +42,7 @@ def uid_to_dn(uid):
 def loginname_to_dn(loginname):
 	if loginname_is_safe(loginname):
 		return 'uid={},{}'.format(loginname, current_app.config["LDAP_BASE_USER"])
-	else:
-		raise Exception('unsafe login name')
+	raise Exception('unsafe login name')
 
 def loginname_is_safe(value):
 	if len(value) > 32 or len(value) < 1:
@@ -68,3 +67,25 @@ def get_next_uid():
 	if uid_to_dn(next_uid):
 		raise Exception('No free uid found')
 	return next_uid
+
+def get_ldap_attribute_safe(ldapobject, attribute):
+	try:
+		result = ldapobject[attribute].value if attribute in ldapobject  else None
+	# we have to catch LDAPCursorError here, because ldap3 in older versions has a broken __contains__ function
+	# see https://github.com/cannatag/ldap3/issues/493
+	# fixed in version 2.5
+	# debian buster ships 2.4.1
+	except LDAPCursorError:
+		result = None
+	return result
+
+def get_ldap_array_attribute_safe(ldapobject, attribute):
+	# if the aray is empty, the attribute does not exist.
+	# if there is only one elemtent, ldap returns a string and not an array with one element
+	# we sanitize this to always be an array
+	result = get_ldap_attribute_safe(ldapobject, attribute)
+	if not result:
+		result = []
+	if isinstance(result, str):
+		result = [result]
+	return result
diff --git a/uffd/role/models.py b/uffd/role/models.py
index f91d9cc2ef98a44684361fe4ebb0bcac0da73199..3b4ca85fe495aaecd060c42eed6c3c2d8ec576a6 100644
--- a/uffd/role/models.py
+++ b/uffd/role/models.py
@@ -21,12 +21,12 @@ class LdapMapping():
 	id = Column(Integer(), primary_key=True, autoincrement=True)
 	dn = Column(String(128))
 	@declared_attr
-	def role_id(cls):
+	def role_id(self):
 		return Column(ForeignKey('role.id'))
 	ldapclass = None
 
 	def get_ldap(self):
-		return self.ldapclass.from_ldap_dn(dn)
+		return self.ldapclass.from_ldap_dn(self.dn)
 
 	def set_ldap(self, value):
 		self.dn = value['dn']
@@ -38,4 +38,3 @@ class RoleGroup(LdapMapping, db.Model):
 class RoleUser(LdapMapping, db.Model):
 	__tablename__ = 'role-user'
 	ldapclass = Group
-
diff --git a/uffd/role/views.py b/uffd/role/views.py
index 8d4a28c8924d5669e81dc2c2b6182115a3d918ba..9863d56554092d170df68fe3072785bbf7df0a25 100644
--- a/uffd/role/views.py
+++ b/uffd/role/views.py
@@ -2,10 +2,8 @@ from flask import Blueprint, render_template, request, url_for, redirect, flash,
 
 from uffd.navbar import register_navbar
 from uffd.csrf import csrf_protect
-from uffd.user.models import User, Group
 from uffd.role.models import Role
 from uffd.session import get_current_user, login_required, is_valid_session
-from uffd.ldap import loginname_to_dn
 from uffd.database import db
 
 bp = Blueprint("role", __name__, template_folder='templates', url_prefix='/role/')
diff --git a/uffd/user/models.py b/uffd/user/models.py
index fb04136e9c86cd6c5c8584e442dba57702ee1027..fa3dbf6695bc760866c463fa0ee255f84059fe6e 100644
--- a/uffd/user/models.py
+++ b/uffd/user/models.py
@@ -16,21 +16,12 @@ class User():
 
 	@classmethod
 	def from_ldap(cls, ldapobject):
-		# if you are in no groups, the "memberOf" attribute does not exist
-		# if you are only in one group, ldap returns a string not an array with one element
-		# we sanitize this to always be an array
-		try:
-			sanitized_groups = ldapobject['memberOf'].value if hasattr(ldapobject, 'memberOf') else []
-		except:
-			sanitized_groups = []
-		if isinstance(sanitized_groups, str):
-			sanitized_groups = [sanitized_groups]
 		return User(
 				uid=ldapobject['uidNumber'].value,
 				loginname=ldapobject['uid'].value,
 				displayname=ldapobject['cn'].value,
 				mail=ldapobject['mail'].value,
-				groups=sanitized_groups,
+				groups=ldap.get_ldap_array_attribute_safe(ldapobject, 'memberOf')
 			)
 
 	@classmethod
@@ -124,21 +115,11 @@ class Group():
 
 	@classmethod
 	def from_ldap(cls, ldapobject):
-		try:
-			description = ldapobject['description'].value if hasattr(ldapobject, 'description') else ''
-		except:
-			description = ''
-		# if a group has no members, "uniqueMember" attribute does not exist
-		# if a group has exactly one member, ldap returns a string not an array with one element
-		# we sanitize this to always be an array
-		sanitized_members = ldapobject['uniqueMember']
-		if isinstance(sanitized_members, str):
-			sanitized_members = [sanitized_members]
 		return Group(
 				gid=ldapobject['gidNumber'].value,
 				name=ldapobject['cn'].value,
-				members=sanitized_members,
-				description=description,
+				members=ldap.get_ldap_array_attribute_safe(ldapobject, 'uniqueMember'),
+				description=ldap.get_ldap_attribute_safe(ldapobject, 'description') or '',
 			)
 
 	@classmethod