diff --git a/geruecht/__init__.py b/geruecht/__init__.py index af71892..0963dd8 100644 --- a/geruecht/__init__.py +++ b/geruecht/__init__.py @@ -7,6 +7,7 @@ from .logger import getLogger from geruecht.controller import dbConfig from flask_mysqldb import MySQL +from flask_ldapconn import LDAPConn LOGGER = getLogger(__name__) LOGGER.info("Initialize App") @@ -23,6 +24,13 @@ app.config['MYSQL_USER'] = dbConfig['user'] app.config['MYSQL_PASSWORD'] = dbConfig['passwd'] app.config['MYSQL_DB'] = dbConfig['database'] app.config['MYSQL_CURSORCLASS'] = 'DictCursor' +app.config['LDAP_SERVER'] = '192.168.5.128' +app.config['LDAP_PORT'] = 389 +app.config['LDAP_BINDDN'] = 'dc=ldap,dc=example,dc=local' +app.config['LDAP_USE_TLS'] = False +app.config['FORCE_ATTRIBUTE_VALUE_AS_LIST'] = True + +ldap = LDAPConn(app) db = MySQL(app) from geruecht import routes diff --git a/geruecht/controller/accesTokenController.py b/geruecht/controller/accesTokenController.py index 160459e..b23e2d1 100644 --- a/geruecht/controller/accesTokenController.py +++ b/geruecht/controller/accesTokenController.py @@ -70,7 +70,7 @@ class AccesTokenController(metaclass=Singleton): LOGGER.info("Found no valid AccessToken with token: {} and group: {}".format(token, group)) return False - def createAccesToken(self, user): + def createAccesToken(self, user, ldap_conn): """ Create an AccessToken Create an AccessToken for an User and add it to the tokenList. @@ -85,7 +85,7 @@ class AccesTokenController(metaclass=Singleton): now = datetime.ctime(datetime.now()) token = hashlib.md5((now + user.dn).encode('utf-8')).hexdigest() self.checkBar(user) - accToken = AccessToken(user, token, datetime.now()) + accToken = AccessToken(user, token, ldap_conn, datetime.now()) LOGGER.debug("Add AccessToken {} to current Tokens".format(accToken)) self.tokenList.append(accToken) LOGGER.info("Finished create AccessToken {} with Token {}".format(accToken, token)) diff --git a/geruecht/controller/databaseController.py b/geruecht/controller/databaseController.py index da45192..3666374 100644 --- a/geruecht/controller/databaseController.py +++ b/geruecht/controller/databaseController.py @@ -4,6 +4,8 @@ from geruecht import db from geruecht.model.user import User from geruecht.model.creditList import CreditList from datetime import datetime, timedelta +from geruecht.exceptions import UsernameExistDB, DatabaseExecption +import traceback class DatabaseController(metaclass=Singleton): ''' @@ -54,10 +56,12 @@ class DatabaseController(metaclass=Singleton): def _convertGroupToString(self, groups): retVal = '' - for group in groups: - if len(retVal) != 0: - retVal += ',' - retVal += group + print('groups: {}'.format(groups)) + if groups: + for group in groups: + if len(retVal) != 0: + retVal += ',' + retVal += group return retVal @@ -71,6 +75,7 @@ class DatabaseController(metaclass=Singleton): def updateUser(self, user): cursor = self.db.connection.cursor() + print('uid: {}; group: {}'.format(user.uid, user.group)) groups = self._convertGroupToString(user.group) sql = "update user set dn='{}', firstname='{}', lastname='{}', gruppe='{}', lockLimit={}, locked={}, autoLock={}, mail='{}' where uid='{}'".format( user.dn, user.firstname, user.lastname, groups, user.limit, user.locked, user.autoLock, user.mail, user.uid) @@ -144,9 +149,26 @@ class DatabaseController(metaclass=Singleton): def deleteWorker(self, user, date): - cursor = self.db.connection.cursor() - cursor.execute("delete from bardienste where user_id={} and startdatetime='{}'".format(user.id, date)) - self.db.connection.commit() + try: + cursor = self.db.connection.cursor() + cursor.execute("delete from bardienste where user_id={} and startdatetime='{}'".format(user.id, date)) + self.db.connection.commit() + except Exception as err: + traceback.print_exc() + + def changeUsername(self, user, newUsername): + try: + cursor= self.db.connection.cursor() + cursor.execute("select * from user where uid='{}'".format(newUsername)) + data = cursor.fetchall() + if data: + raise UsernameExistDB("Username already exists") + else: + cursor.execute("update user set uid='{}' where id={}".format(newUsername, user.id)) + self.db.connection() + except Exception as err: + traceback.print_exc() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) if __name__ == '__main__': db = DatabaseController() diff --git a/geruecht/controller/ldapController.py b/geruecht/controller/ldapController.py index 7002f44..1356c45 100644 --- a/geruecht/controller/ldapController.py +++ b/geruecht/controller/ldapController.py @@ -1,72 +1,75 @@ -import ldap +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 from geruecht.exceptions import PermissionDenied from . import Singleton +from geruecht.exceptions import UsernameExistLDAP, LDAPExcetpion +import traceback class LDAPController(metaclass=Singleton): ''' Authentification over LDAP. Create Account on-the-fly ''' - def __init__(self, url="ldap://192.168.5.108", dn='dc=ldap,dc=example,dc=local'): - self.url = url + def __init__(self, dn='dc=ldap,dc=example,dc=local'): self.dn = dn - self.connect() + self.ldap = ldap - def connect(self): - try: - self.client = ldap.initialize(self.url, bytes_mode=False) - except Exception as err: - raise err def login(self, username, password): - self.connect() try: - cn = self.client.search_s("ou=user,{}".format(self.dn), ldap.SCOPE_SUBTREE, 'uid={}'.format(username),['cn'])[0][1]['cn'][0].decode('utf-8') - self.client.bind_s("cn={},ou=user,{}".format(cn, self.dn), password) - self.client.unbind_s() - except: - self.client.unbind_s() - raise PermissionDenied("Invalid Password or Username") + retVal = self.ldap.authenticate(username, password, 'uid', self.dn) + if not retVal: + raise PermissionDenied("Invalid Password or Username") + except Exception as err: + traceback.print_exception(err) + raise PermissionDenied("Wrong username or password.") + + def bind(self, user, password): + ldap_conn = self.ldap.connect(user.dn, password) + return ldap_conn def getUserData(self, username): try: - self.connect() - search_data = self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'uid={}'.format(username), ['uid', 'givenName', 'sn', 'mail']) - retVal = search_data[0][1] - for k,v in retVal.items(): - retVal[k] = v[0].decode('utf-8') - retVal['dn'] = self.dn - retVal['firstname'] = retVal['givenName'] - retVal['lastname'] = retVal['sn'] + 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'] + retVal = { + 'dn': self.ldap.connection.response[0]['dn'], + 'firstname': user['givenName'][0], + 'lastname': user['sn'][0], + 'uid': username + } return retVal except: raise PermissionDenied("No User exists with this uid.") def getGroup(self, username): - retVal = [] - self.connect() - main_group_data = self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'uid={}'.format(username), ['gidNumber']) - if main_group_data: - main_group_number = main_group_data[0][1]['gidNumber'][0].decode('utf-8') - group_data = self.client.search_s('ou=group,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'gidNumber={}'.format(main_group_number), ['cn']) - if group_data: - group_name = group_data[0][1]['cn'][0].decode('utf-8') + try: + retVal = [] + self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid={})'.format(username), SUBTREE, attributes=['gidNumber']) + response = self.ldap.connection.response + main_group_number = self.ldap.connection.response[0]['attributes']['gidNumber'] + if main_group_number: + group_data = 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] if group_name == 'ldap-user': retVal.append(USER) - groups_data = self.client.search_s('ou=group,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'memberUID={}'.format(username), ['cn']) - for data in groups_data: - print(data[1]['cn'][0].decode('utf-8')) - group_name = data[1]['cn'][0].decode('utf-8') - if group_name == 'finanzer': - retVal.append(MONEY) - elif group_name == 'gastro': - retVal.append(GASTRO) - elif group_name == 'bar': - retVal.append(BAR) - return retVal + self.ldap.connection.search('ou=group,{}'.format(self.dn), '(memberUID={})'.format(username), SUBTREE, attributes=['cn']) + groups_data = self.ldap.connection.response + for data in groups_data: + group_name = data['attributes']['cn'][0] + if group_name == 'finanzer': + retVal.append(MONEY) + elif group_name == 'gastro': + retVal.append(GASTRO) + elif group_name == 'bar': + retVal.append(BAR) + return retVal + except Exception as err: + traceback.print_exc() def __isUserInList(self, list, username): help_list = [] @@ -77,19 +80,19 @@ class LDAPController(metaclass=Singleton): return False def getAllUser(self): - self.connect() retVal = [] - data = self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, attrlist=['uid', 'givenName', 'sn', 'mail']) + self.ldap.connection.search() + self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE, attributes=['uid', 'givenName', 'sn', 'mail']) + data = self.ldap.connection.response for user in data: - if 'uid' in user[1]: - username = user[1]['uid'][0].decode('utf-8') - firstname = user[1]['givenName'][0].decode('utf-8') - lastname = user[1]['sn'][0].decode('utf-8') + 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}) return retVal def searchUser(self, searchString): - self.connect() name = searchString.split(" ") @@ -103,29 +106,57 @@ class LDAPController(metaclass=Singleton): if len(name) == 1: if name[0] == "**": - name_result.append(self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, - attrlist=['uid', 'givenName', 'sn'])) + self.ldap.connection.search('ou=user,{}'.format(self.dn), '(uid=*)', SUBTREE, + attributes=['uid', 'givenName', 'sn']) + name_result.append(self.ldap.connection.response) else: - name_result.append(self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'givenName={}'.format(name[0]), ['uid', 'givenName', 'sn', 'mail'])) - name_result.append(self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'sn={}'.format(name[0]),['uid', 'givenName', 'sn'], 'mail')) + 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: - name_result.append(self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, - 'givenName={}'.format(name[1]), ['uid', 'givenName', 'sn'])) - name_result.append(self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'sn={}'.format(name[1]), - ['uid', 'givenName', 'sn', 'mail'])) + 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[1]: - username = user[1]['uid'][0].decode('utf-8') + if 'uid' in user['attributes']: + username = user['attributes']['uid'][0] if not self.__isUserInList(retVal, username): - firstname = user[1]['givenName'][0].decode('utf-8') - lastname = user[1]['sn'][0].decode('utf-8') + 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): + try: + if 'username' in attributes: + conn.search('ou=user,{}'.format(self.dn), '(uid={})'.format(attributes['username'])) + if conn.entries: + 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])] + conn.modify(user.dn, mody) + except Exception as err: + traceback.print_exc() + raise LDAPExcetpion("Something went wrong in LDAP: {}".format(err)) + + if __name__ == '__main__': a = LDAPController() diff --git a/geruecht/controller/userController.py b/geruecht/controller/userController.py index 1590749..6d551c8 100644 --- a/geruecht/controller/userController.py +++ b/geruecht/controller/userController.py @@ -5,9 +5,10 @@ import geruecht.controller.emailController as ec from geruecht.model.user import User from geruecht.exceptions import PermissionDenied from datetime import datetime, timedelta +from geruecht.exceptions import UsernameExistLDAP, UsernameExistDB, DatabaseExecption, LDAPExcetpion db = dc.DatabaseController() -ldap = lc.LDAPController(ldapConfig['URL'], ldapConfig['dn']) +ldap = lc.LDAPController(ldapConfig['dn']) emailController = ec.EmailController(mailConfig['URL'], mailConfig['user'], mailConfig['passwd'], mailConfig['port'], mailConfig['email']) class UserController(metaclass=Singleton): @@ -128,10 +129,31 @@ class UserController(metaclass=Singleton): retVal.append(self.sendMail(user)) return retVal + def modifyUser(self, user, ldap_conn, attributes): + try: + if 'username' in attributes: + db.changeUsername(user, attributes['username']) + ldap.modifyUser(user, ldap_conn, attributes) + if 'username' in attributes: + return self.getUser(attributes['username']) + else: + return self.getUser(user.uid) + except UsernameExistLDAP as err: + 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 Exception as err: + raise Exception(err) + def loginUser(self, username, password): try: user = self.getUser(username) + user.password = password ldap.login(username, password) - return user + ldap_conn = ldap.bind(user, password) + return user, ldap_conn except PermissionDenied as err: raise err diff --git a/geruecht/exceptions/__init__.py b/geruecht/exceptions/__init__.py index 30bba52..6aeaf8e 100644 --- a/geruecht/exceptions/__init__.py +++ b/geruecht/exceptions/__init__.py @@ -1,2 +1,10 @@ class PermissionDenied(Exception): + pass +class UsernameExistDB(Exception): + pass +class UsernameExistLDAP(Exception): + pass +class DatabaseExecption(Exception): + pass +class LDAPExcetpion(Exception): pass \ No newline at end of file diff --git a/geruecht/finanzer/routes.py b/geruecht/finanzer/routes.py index 92d7be1..d6f1a57 100644 --- a/geruecht/finanzer/routes.py +++ b/geruecht/finanzer/routes.py @@ -4,6 +4,7 @@ from datetime import datetime import geruecht.controller.userController as uc from geruecht.model import MONEY from geruecht.decorator import login_required +import time finanzer = Blueprint("finanzer", __name__) diff --git a/geruecht/model/accessToken.py b/geruecht/model/accessToken.py index 0718dc4..f63db6c 100644 --- a/geruecht/model/accessToken.py +++ b/geruecht/model/accessToken.py @@ -15,8 +15,9 @@ class AccessToken(): timestamp = None user = None token = None + ldap_conn = None - def __init__(self, user, token, timestamp=datetime.now()): + def __init__(self, user, token, ldap_conn, timestamp=datetime.now()): """ Initialize Class AccessToken No more to say. @@ -30,6 +31,7 @@ class AccessToken(): self.user = user self.timestamp = timestamp self.token = token + self.ldap_conn = ldap_conn def updateTimestamp(self): """ Update the Timestamp diff --git a/geruecht/model/user.py b/geruecht/model/user.py index 925ca37..23460fb 100644 --- a/geruecht/model/user.py +++ b/geruecht/model/user.py @@ -49,6 +49,7 @@ class User(): self.group = data['gruppe'].split(',') if 'creditLists' in data: self.geruechte = data['creditLists'] + self.password = '' def updateData(self, data): if 'dn' in data: @@ -204,7 +205,8 @@ class User(): "username": self.uid, "locked": self.locked, "autoLock": self.autoLock, - "limit": self.limit + "limit": self.limit, + "mail": self.mail } return dic diff --git a/geruecht/routes.py b/geruecht/routes.py index daf8d78..bd71ea5 100644 --- a/geruecht/routes.py +++ b/geruecht/routes.py @@ -48,9 +48,9 @@ def _login(): password = data['password'] LOGGER.info("search {} in database".format(username)) try: - user = userController.loginUser(username, password) + user, ldap_conn = userController.loginUser(username, password) user.password = password - token = accesTokenController.createAccesToken(user) + token = accesTokenController.createAccesToken(user, ldap_conn) dic = accesTokenController.validateAccessToken(token, [USER]).user.toJSON() dic["token"] = token dic["accessToken"] = token @@ -58,5 +58,7 @@ def _login(): return jsonify(dic) except PermissionDenied as err: return jsonify({"error": str(err)}), 401 + except Exception: + return jsonify({"error": "permission denied"}), 401 LOGGER.info("User {} does not exist.".format(username)) return jsonify({"error": "wrong username"}), 401 diff --git a/geruecht/user/routes.py b/geruecht/user/routes.py index 5b30297..139a96a 100644 --- a/geruecht/user/routes.py +++ b/geruecht/user/routes.py @@ -3,6 +3,8 @@ from geruecht.decorator import login_required import geruecht.controller.userController as uc from geruecht.model import USER from datetime import datetime +import time +import traceback user = Blueprint("user", __name__) @@ -33,4 +35,42 @@ def _addAmount(**kwargs): retVal = accToken.user.toJSON() retVal['creditList'] = {credit.year: credit.toJSON() for credit in accToken.user.geruechte} return jsonify(retVal) - return jsonify({"error": "something went wrong"}), 500 \ No newline at end of file + return jsonify({"error": "something went wrong"}), 500 + +@user.route("/user/saveConfig", methods=['POST']) +@login_required(groups=[USER]) +def _saveConfig(**kwargs): + try: + if 'accToken' in kwargs: + accToken = kwargs['accToken'] + data = request.get_json() + accToken.user = userController.modifyUser(accToken.user, accToken.ldap_conn, data) + retVal = accToken.user.toJSON() + retVal['creditList'] = {credit.year: credit.toJSON() for credit in accToken.user.geruechte} + return jsonify(retVal) + except Exception as err: + return jsonify({"error": err}), 409 + +@user.route("/user/job", methods=['POST']) +@login_required(groups=[USER]) +def _getJob(**kwargs): + try: + if 'accToken' in kwargs: + accToken = kwargs['accToken'] + data = request.get_json() + date = datetime.utcfromtimestamp(int(data['date'])) + test = userController.getWorker(date, username=accToken.user.uid) + if test == [None]: + job = False + else: + job = True + if job: + workers = userController.getWorker(date) + for worker in workers: + if worker['user']['uid'] == accToken.user.uid: + workers.remove(worker) + return jsonify({'job': job, 'workers': workers}) + return jsonify({'job': job}) + except Exception as err: + traceback.print_exc() + return jsonify({"error": str(err)}), 409 \ No newline at end of file diff --git a/geruecht/vorstand/routes.py b/geruecht/vorstand/routes.py index d1184dc..35e375b 100644 --- a/geruecht/vorstand/routes.py +++ b/geruecht/vorstand/routes.py @@ -3,6 +3,7 @@ from datetime import datetime import geruecht.controller.userController as uc from geruecht.decorator import login_required from geruecht.model import MONEY, GASTRO +import time vorstand = Blueprint("vorstand", __name__) userController = uc.UserController()