Added LDAP authentification plugin

This commit is contained in:
Ferdinand Thiessen 2020-08-25 04:36:05 +02:00
parent 7d8fa4f630
commit 53d502336e
3 changed files with 190 additions and 215 deletions

View File

@ -1,20 +1,193 @@
import flaschengeist.modules as modules import flaschengeist.modules as modules
from flaschengeist import logger
from flask import current_app as app from flask import current_app as app
from flask_ldapconn import LDAPConn
from ldap3 import SUBTREE#, MODIFY_REPLACE, HASHED_SALTED_MD5
import ssl
class AuthLDAP(modules.Auth):
_default = {
'PORT': '389',
'USE_SSL': 'False'
}
class AuthPlain(modules.Auth):
def configure(self, config): def configure(self, config):
for name in self._default:
if name not in config:
config[name] = self._default[name]
app.config.update( app.config.update(
'LDAP_SERVER' = config['URL'], LDAP_SERVER = config['URL'],
'LDAP_PORT' = config['PORT'], LDAP_PORT = config.getint('PORT'),
'LDAP_BINDDN' = config['BINDDN'], LDAP_BINDDN = config['BINDDN'],
'LDAP_SECRET' = config['SECRET'] LDAP_USE_TLS = False,
'LDAP_USE_SSL' = config['USE_SSL'], LDAP_USE_SSL = config.getboolean('USE_SSL'),
'LDAP_TLS_VERSION' = ssl.PROTOCOL_TLSv1_2, LDAP_TLS_VERSION = ssl.PROTOCOL_TLSv1_2,
'LDAP_REQUIRE_CERT' = ssl.CERT_NONE, LDAP_REQUIRE_CERT = ssl.CERT_NONE,
'FORCE_ATTRIBUTE_VALUE_AS_LIST' = True FORCE_ATTRIBUTE_VALUE_AS_LIST = True
) )
if 'SECRET' in config:
app.config['LDAP_SECRET'] = config['SECRET'],
self.ldap = LDAPConn(app)
self.dn = config['BASEDN']
def login(self, user, password): def login(self, user, password):
if not user: if not user:
return False return False
try:
r = self.ldap.authenticate(user.uid, password, 'uid', self.dn)
return r == True
except Exception as err:
logger.warning("Exception while login into ldap", exc_info=True)
return False return False
def modifyUser(self, user):
try:
ldap_conn = self.ldap.bind(user.uid, password)
if attributes:
if 'username' in attributes:
debug.debug("change username, so change first in database")
db.changeUsername(user, attributes['username'])
ldap.modifyUser(user, ldap_conn, attributes)
if 'username' in attributes:
retVal = self.getUser(attributes['username'])
debug.debug("user is {{ {} }}".format(retVal))
return retVal
else:
retVal = self.getUser(user.uid)
debug.debug("user is {{ {} }}".format(retVal))
return retVal
return self.getUser(user.uid)
except UsernameExistLDAP as err:
debug.debug(
"username exists on ldap, rechange username on database", exc_info=True)
db.changeUsername(user, user.uid)
raise Exception(err)
except LDAPExcetpion as err:
if 'username' in attributes:
db.changeUsername(user, user.uid)
raise Exception(err)
except LDAPPasswordIsMandatoryError as err:
raise Exception('Password wurde nicht gesetzt!!')
except LDAPBindError as err:
raise Exception('Password ist falsch')
except Exception as err:
raise Exception(err)
debug.info("modify ldap data from user {{ {} }} with attributes (can't show because here can be a password)".format(user))
try:
if 'username' in attributes:
debug.debug("change username")
conn.search('ou=user,{}'.format(self.dn), '(uid={})'.format(attributes['username']))
if conn.entries:
debug.warning("username already exists", exc_info=True)
raise UsernameExistLDAP("Username already exists in LDAP")
#create modifyer
mody = {}
if 'username' in attributes:
mody['uid'] = [(MODIFY_REPLACE, [attributes['username']])]
if 'firstname' in attributes:
mody['givenName'] = [(MODIFY_REPLACE, [attributes['firstname']])]
if 'lastname' in attributes:
mody['sn'] = [(MODIFY_REPLACE, [attributes['lastname']])]
if 'mail' in attributes:
mody['mail'] = [(MODIFY_REPLACE, [attributes['mail']])]
if 'password' in attributes:
salted_password = hashed(HASHED_SALTED_MD5, attributes['password'])
mody['userPassword'] = [(MODIFY_REPLACE, [salted_password])]
debug.debug("modyfier are (can't show because here can be a password)")
conn.modify(user.dn, mody)
except Exception as err:
debug.warning("exception in modify user data from ldap", exc_info=True)
raise LDAPExcetpion("Something went wrong in LDAP: {}".format(err))
def updateUser(self, user):
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid={})'.format(user.uid), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
r = self.ldap.connection.response[0]['attributes']
if r['uid'][0] == user.uid:
user.setAttribute('DN', self.ldap.connection.response[0]['dn'])
user.firstname = r['givenName'][0]
user.lastname = r['sn'][0]
if r['mail']:
user.mail = r['mail'][0]
if 'displayName' in r:
user.displayname = r['displayName'][0]
for group in self._getGroups(user.uid):
user.addGroup(group)
def _getGroups(self, uid):
try:
groups = []
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid={})'.format(uid), SUBTREE, attributes=['gidNumber'])
main_group_number = self.ldap.connection.response[0]['attributes']['gidNumber']
if main_group_number:
if type(main_group_number) is list:
main_group_number = main_group_number[0]
self.ldap.connection.search('ou=group,{}'.format(self.dn), '(gidNumber={})'.format(main_group_number), attributes=['cn'])
groups.append(self.ldap.connection.response[0]['attributes']['cn'][0])
self.ldap.connection.search('ou=group,{}'.format(self.dn), '(memberUID={})'.format(uid), SUBTREE, attributes=['cn'])
groups_data = self.ldap.connection.response
for data in groups_data:
groups.append(data['attributes']['cn'][0])
return groups
except Exception as err:
debug.warning("exception in get groups from ldap", exc_info=True)
return []
# def getAllUser(self):
# debug.info("get all users from ldap")
# retVal = []
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
# data = self.ldap.connection.response
# debug.debug("data is {{ {} }}".format(data))
# for user in data:
# if 'uid' in user['attributes']:
# username = user['attributes']['uid'][0]
# firstname = user['attributes']['givenName'][0]
# lastname = user['attributes']['sn'][0]
# retVal.append({'username': username, 'firstname': firstname, 'lastname': lastname})
# debug.debug("users are {{ {} }}".format(retVal))
# return retVal
# def searchUser(self, searchString):
#
# name = searchString.split(" ")
#
# for i in range(len(name)):
# name[i] = "*"+name[i]+"*"
#
#
# print(name)
#
# name_result = []
#
# if len(name) == 1:
# if name[0] == "**":
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE,
# attributes=['uid', 'givenName', 'sn'])
# name_result.append(self.ldap.connection.response)
# else:
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(givenName={})'.format(name[0]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
# name_result.append(self.ldap.connection.response)
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(sn={})'.format(name[0]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
# name_result.append(self.ldap.connection.response)
# else:
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(givenName={})'.format(name[1]), SUBTREE, attributes=['uid', 'givenName', 'sn'])
# name_result.append(self.ldap.connection.response)
# self.ldap.connection.search('ou=user,{}'.format(self.dn), '(sn={})'.format(name[1]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
# name_result.append(self.ldap.connection.response)
# retVal = []
# for names in name_result:
# for user in names:
# if 'uid' in user['attributes']:
# username = user['attributes']['uid'][0]
# if not self.__isUserInList(retVal, username):
# firstname = user['attributes']['givenName'][0]
# lastname = user['attributes']['sn'][0]
# retVal.append({'username': username, 'firstname': firstname, 'lastname': lastname})
#
# return retVal

View File

@ -1,204 +0,0 @@
from geruecht import ldap
from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_MD5
from ldap3.utils.hashed import hashed
from geruecht.model import MONEY, USER, GASTRO, BAR, VORSTAND, EXTERN
from geruecht.exceptions import PermissionDenied
from . import Singleton
from geruecht.exceptions import UsernameExistLDAP, LDAPExcetpion
from . import ldapConfig
from geruecht.logger import getDebugLogger
debug = getDebugLogger()
class LDAPController(metaclass=Singleton):
'''
Authentification over LDAP. Create Account on-the-fly
'''
def __init__(self):
debug.info("init ldap controller")
self.dn = ldapConfig['DN']
self.ldap = ldap
debug.debug("base dn is {{ {} }}".format(self.dn))
debug.debug("ldap is {{ {} }}".format(self.ldap))
def login(self, username, password):
debug.info("login user {{ {} }} in ldap")
try:
retVal = self.ldap.authenticate(username, password, 'uid', self.dn)
debug.debug("authentification to ldap is {{ {} }}".format(retVal))
if not retVal:
debug.debug("authenification is incorrect")
raise PermissionDenied("Invalid Password or Username")
except Exception as err:
debug.warning("exception while login into ldap", exc_info=True)
raise PermissionDenied("Invalid Password or Username. {}".format(err))
def bind(self, user, password):
debug.info("bind user {{ {} }} to ldap")
ldap_conn = self.ldap.connect(user.dn, password)
debug.debug("ldap_conn is {{ {} }}".format(ldap_conn))
return ldap_conn
def getUserData(self, username):
debug.info("get user data from ldap of user {{ {} }}".format(username))
try:
debug.debug("search user in ldap")
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid={})'.format(username), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
user = self.ldap.connection.response[0]['attributes']
debug.debug("user is {{ {} }}".format(user))
retVal = {
'dn': self.ldap.connection.response[0]['dn'],
'firstname': user['givenName'][0],
'lastname': user['sn'][0],
'uid': user['uid'][0],
}
if user['mail']:
retVal['mail'] = user['mail'][0]
debug.debug("user is {{ {} }}".format(retVal))
if retVal['uid'] == username:
return retVal
else:
raise Exception()
except:
debug.warning("exception in get user data from ldap", exc_info=True)
raise PermissionDenied("No User exists with this uid.")
def getGroup(self, username):
debug.info("get group from user {{ {} }}".format(username))
try:
retVal = []
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid={})'.format(username), SUBTREE, attributes=['gidNumber'])
main_group_number = self.ldap.connection.response[0]['attributes']['gidNumber']
debug.debug("main group number is {{ {} }}".format(main_group_number))
if main_group_number:
if type(main_group_number) is list:
main_group_number = main_group_number[0]
self.ldap.connection.search('ou=group,{}'.format(self.dn), '(gidNumber={})'.format(main_group_number), attributes=['cn'])
group_name = self.ldap.connection.response[0]['attributes']['cn'][0]
debug.debug("group name is {{ {} }}".format(group_name))
if group_name == 'ldap-user':
retVal.append(USER)
if group_name == 'extern':
retVal.append(EXTERN)
self.ldap.connection.search('ou=group,{}'.format(self.dn), '(memberUID={})'.format(username), SUBTREE, attributes=['cn'])
groups_data = self.ldap.connection.response
debug.debug("groups number is {{ {} }}".format(groups_data))
for data in groups_data:
group_name = data['attributes']['cn'][0]
debug.debug("group name is {{ {} }}".format(group_name))
if group_name == 'finanzer':
retVal.append(MONEY)
elif group_name == 'gastro':
retVal.append(GASTRO)
elif group_name == 'bar':
retVal.append(BAR)
elif group_name == 'vorstand':
retVal.append(VORSTAND)
elif group_name == 'ldap-user':
retVal.append(USER)
debug.debug("groups are {{ {} }}".format(retVal))
return retVal
except Exception as err:
debug.warning("exception in get groups from ldap", exc_info=True)
raise LDAPExcetpion(str(err))
def __isUserInList(self, list, username):
help_list = []
for user in list:
help_list.append(user['username'])
if username in help_list:
return True
return False
def getAllUser(self):
debug.info("get all users from ldap")
retVal = []
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
data = self.ldap.connection.response
debug.debug("data is {{ {} }}".format(data))
for user in data:
if 'uid' in user['attributes']:
username = user['attributes']['uid'][0]
firstname = user['attributes']['givenName'][0]
lastname = user['attributes']['sn'][0]
retVal.append({'username': username, 'firstname': firstname, 'lastname': lastname})
debug.debug("users are {{ {} }}".format(retVal))
return retVal
def searchUser(self, searchString):
name = searchString.split(" ")
for i in range(len(name)):
name[i] = "*"+name[i]+"*"
print(name)
name_result = []
if len(name) == 1:
if name[0] == "**":
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE,
attributes=['uid', 'givenName', 'sn'])
name_result.append(self.ldap.connection.response)
else:
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(givenName={})'.format(name[0]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
name_result.append(self.ldap.connection.response)
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(sn={})'.format(name[0]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
name_result.append(self.ldap.connection.response)
else:
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(givenName={})'.format(name[1]), SUBTREE, attributes=['uid', 'givenName', 'sn'])
name_result.append(self.ldap.connection.response)
self.ldap.connection.search('ou=user,{}'.format(self.dn), '(sn={})'.format(name[1]), SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail'])
name_result.append(self.ldap.connection.response)
retVal = []
for names in name_result:
for user in names:
if 'uid' in user['attributes']:
username = user['attributes']['uid'][0]
if not self.__isUserInList(retVal, username):
firstname = user['attributes']['givenName'][0]
lastname = user['attributes']['sn'][0]
retVal.append({'username': username, 'firstname': firstname, 'lastname': lastname})
return retVal
def modifyUser(self, user, conn, attributes):
debug.info("modify ldap data from user {{ {} }} with attributes (can't show because here can be a password)".format(user))
try:
if 'username' in attributes:
debug.debug("change username")
conn.search('ou=user,{}'.format(self.dn), '(uid={})'.format(attributes['username']))
if conn.entries:
debug.warning("username already exists", exc_info=True)
raise UsernameExistLDAP("Username already exists in LDAP")
#create modifyer
mody = {}
if 'username' in attributes:
mody['uid'] = [(MODIFY_REPLACE, [attributes['username']])]
if 'firstname' in attributes:
mody['givenName'] = [(MODIFY_REPLACE, [attributes['firstname']])]
if 'lastname' in attributes:
mody['sn'] = [(MODIFY_REPLACE, [attributes['lastname']])]
if 'mail' in attributes:
mody['mail'] = [(MODIFY_REPLACE, [attributes['mail']])]
if 'password' in attributes:
salted_password = hashed(HASHED_SALTED_MD5, attributes['password'])
mody['userPassword'] = [(MODIFY_REPLACE, [salted_password])]
debug.debug("modyfier are (can't show because here can be a password)")
conn.modify(user.dn, mody)
except Exception as err:
debug.warning("exception in modify user data from ldap", exc_info=True)
raise LDAPExcetpion("Something went wrong in LDAP: {}".format(err))
if __name__ == '__main__':
a = LDAPController()
a.getUserData('jhille')

View File

@ -10,14 +10,20 @@ setup(
packages=find_packages(), packages=find_packages(),
package_data={'': ['*.yml']}, package_data={'': ['*.yml']},
scripts=['run_flaschengeist'], scripts=['run_flaschengeist'],
install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", "flask_ldapconn", "flask_cors"], install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", "flask_cors"],
extras_require={
'ldap': [
'flask_ldapconn',
'ldap3'
]
},
entry_points = { entry_points = {
'flaschengeist.plugin': [ 'flaschengeist.plugin': [
'auth = flaschengeist.modules.auth:register' 'auth = flaschengeist.modules.auth:register'
], ],
'flaschengeist.auth': [ 'flaschengeist.auth': [
'auth_plain = flaschengeist.modules.auth_plain:AuthPlain', 'auth_plain = flaschengeist.modules.auth_plain:AuthPlain',
'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP' 'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]'
] ]
} }
) )