Added LDAP authentification plugin
This commit is contained in:
parent
7d8fa4f630
commit
53d502336e
|
@ -1,20 +1,193 @@
|
|||
import flaschengeist.modules as modules
|
||||
from flaschengeist import logger
|
||||
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):
|
||||
for name in self._default:
|
||||
if name not in config:
|
||||
config[name] = self._default[name]
|
||||
|
||||
app.config.update(
|
||||
'LDAP_SERVER' = config['URL'],
|
||||
'LDAP_PORT' = config['PORT'],
|
||||
'LDAP_BINDDN' = config['BINDDN'],
|
||||
'LDAP_SECRET' = config['SECRET']
|
||||
'LDAP_USE_SSL' = config['USE_SSL'],
|
||||
'LDAP_TLS_VERSION' = ssl.PROTOCOL_TLSv1_2,
|
||||
'LDAP_REQUIRE_CERT' = ssl.CERT_NONE,
|
||||
'FORCE_ATTRIBUTE_VALUE_AS_LIST' = True
|
||||
LDAP_SERVER = config['URL'],
|
||||
LDAP_PORT = config.getint('PORT'),
|
||||
LDAP_BINDDN = config['BINDDN'],
|
||||
LDAP_USE_TLS = False,
|
||||
LDAP_USE_SSL = config.getboolean('USE_SSL'),
|
||||
LDAP_TLS_VERSION = ssl.PROTOCOL_TLSv1_2,
|
||||
LDAP_REQUIRE_CERT = ssl.CERT_NONE,
|
||||
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):
|
||||
if not user:
|
||||
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
|
||||
|
||||
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
|
||||
|
|
|
@ -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')
|
10
setup.py
10
setup.py
|
@ -10,14 +10,20 @@ setup(
|
|||
packages=find_packages(),
|
||||
package_data={'': ['*.yml']},
|
||||
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 = {
|
||||
'flaschengeist.plugin': [
|
||||
'auth = flaschengeist.modules.auth:register'
|
||||
],
|
||||
'flaschengeist.auth': [
|
||||
'auth_plain = flaschengeist.modules.auth_plain:AuthPlain',
|
||||
'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP'
|
||||
'auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]'
|
||||
]
|
||||
}
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue