diff --git a/geruecht/controller/accesTokenController.py b/geruecht/controller/accesTokenController.py index 6c683c4..58675e2 100644 --- a/geruecht/controller/accesTokenController.py +++ b/geruecht/controller/accesTokenController.py @@ -1,6 +1,7 @@ from geruecht.model.accessToken import AccessToken import geruecht.controller as gc import geruecht.controller.mainController as mc +import geruecht.controller.databaseController as dc from geruecht.model import BAR from datetime import datetime, timedelta import hashlib @@ -10,6 +11,7 @@ from geruecht.logger import getDebugLogger debug = getDebugLogger() mainController = mc.MainController() +db = dc.DatabaseController() class AccesTokenController(metaclass=Singleton): """ Control all createt AccesToken @@ -30,7 +32,6 @@ class AccesTokenController(metaclass=Singleton): """ debug.info("init accesstoken controller") self.lifetime = gc.accConfig - self.tokenList = [] def checkBar(self, user): debug.info("check if user {{ {} }} is baruser".format(user)) @@ -57,7 +58,7 @@ class AccesTokenController(metaclass=Singleton): An the AccesToken for this given Token or False. """ debug.info("check token {{ {} }} is valid") - for accToken in self.tokenList: + for accToken in db.getAccessTokens(): debug.debug("accesstoken is {}".format(accToken)) endTime = accToken.timestamp + timedelta(seconds=accToken.lifetime) now = datetime.now() @@ -69,19 +70,16 @@ class AccesTokenController(metaclass=Singleton): debug.debug("check if accestoken {{ {} }} has group {{ {} }}".format(accToken, group)) if self.isSameGroup(accToken, group): accToken.updateTimestamp() + db.updateAccessToken(accToken) debug.debug("found accesstoken {{ {} }} with token: {{ {} }} and group: {{ {} }}".format(accToken, token, group)) return accToken else: debug.debug("accesstoken is {{ {} }} out of date".format(accToken)) - self.deleteAccessToken(accToken) + db.deleteAccessToken(accToken) debug.debug("no valid accesstoken with token: {{ {} }} and group: {{ {} }}".format(token, group)) return False - def deleteAccessToken(self, accToken): - debug.info("delete accesstoken {{ {} }}".format(accToken)) - self.tokenList.remove(accToken) - - def createAccesToken(self, user, ldap_conn): + def createAccesToken(self, user, user_agent=None): """ Create an AccessToken Create an AccessToken for an User and add it to the tokenList. @@ -96,9 +94,8 @@ 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, ldap_conn, self.lifetime, datetime.now()) + accToken = db.createAccessToken(user, token, self.lifetime, datetime.now(), lock_bar=False, user_agent=user_agent) debug.debug("accesstoken is {{ {} }}".format(accToken)) - self.tokenList.append(accToken) return token def isSameGroup(self, accToken, groups): @@ -117,3 +114,13 @@ class AccesTokenController(metaclass=Singleton): for group in groups: if group in accToken.user.group: return True return False + + def getAccessTokensFromUser(self, user): + return db.getAccessTokensFromUser(user) + + def deleteAccessToken(self, accToken): + db.deleteAccessToken(accToken) + + def updateAccessToken(self, accToken): + accToken.updateTimestamp() + return db.updateAccessToken(accToken) diff --git a/geruecht/controller/databaseController/__init__.py b/geruecht/controller/databaseController/__init__.py index 9ab55bb..08ee142 100644 --- a/geruecht/controller/databaseController/__init__.py +++ b/geruecht/controller/databaseController/__init__.py @@ -1,6 +1,6 @@ from ..mainController import Singleton from geruecht import db -from ..databaseController import dbUserController, dbCreditListController, dbJobKindController, dbPricelistController, dbWorkerController, dbWorkgroupController, dbJobInviteController, dbJobRequesController +from ..databaseController import dbUserController, dbCreditListController, dbJobKindController, dbPricelistController, dbWorkerController, dbWorkgroupController, dbJobInviteController, dbJobRequesController, dbAccessTokenController from geruecht.exceptions import DatabaseExecption import traceback from MySQLdb._exceptions import IntegrityError @@ -13,6 +13,7 @@ class DatabaseController(dbUserController.Base, dbJobKindController.Base, dbJobInviteController.Base, dbJobRequesController.Base, + dbAccessTokenController.Base, metaclass=Singleton): ''' DatabaesController diff --git a/geruecht/controller/databaseController/dbAccessTokenController.py b/geruecht/controller/databaseController/dbAccessTokenController.py new file mode 100644 index 0000000..2182976 --- /dev/null +++ b/geruecht/controller/databaseController/dbAccessTokenController.py @@ -0,0 +1,82 @@ +import traceback +from geruecht.exceptions import DatabaseExecption +from geruecht.model.accessToken import AccessToken + + +class Base: + + def getAccessToken(self, item): + try: + cursor = self.db.connection.cursor() + if type(item) == str: + sql = "select * from session where token='{}'".format(item) + elif type(item) == int: + sql = 'select * from session where id={}'.format(item) + else: + raise DatabaseExecption("item as no type int or str. name={}, type={}".format(item, type(item))) + cursor.execute(sql) + session = cursor.fetchone() + retVal = AccessToken(session['id'], self.getUserById(session['user']), session['token'], session['lifetime'], session['timestamp'], browser=session['browser'], platform=session['platform']) if session != None else None + return retVal + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Databes: {}".format(err)) + + def getAccessTokensFromUser(self, user): + try: + cursor = self.db.connection.cursor() + cursor.execute("select * from session where user={}".format(user.id)) + sessions = cursor.fetchall() + retVal = [ + AccessToken(session['id'], self.getUserById(session['user']), session['token'], session['lifetime'], + session['timestamp'], browser=session['browser'], platform=session['platform']) for session in sessions] + return retVal + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) + + def getAccessTokens(self): + try: + cursor = self.db.connection.cursor() + cursor.execute("select * from session") + sessions = cursor.fetchall() + retVal = [AccessToken(session['id'], self.getUserById(session['user']), session['token'], session['lifetime'], session['timestamp'], browser=session['browser'], platform=session['platform']) for session in sessions] + return retVal + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) + + def createAccessToken(self, user, token, lifetime, timestamp, lock_bar, user_agent=None): + try: + cursor = self.db.connection.cursor() + cursor.execute("insert into session (user, timestamp, lock_bar, token, lifetime, browser, platform) VALUES ({}, '{}', {}, '{}', {}, '{}', '{}')".format(user.id, timestamp, lock_bar, token, lifetime, user_agent.browser if user_agent else 'NULL', user_agent.platform if user_agent else 'NULL')) + self.db.connection.commit() + return self.getAccessToken(token) + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) + + def updateAccessToken(self, accToken): + try: + cursor = self.db.connection.cursor() + cursor.execute("update session set timestamp='{}', lock_bar={}, lifetime={} where id={}".format(accToken.timestamp, accToken.lock_bar, accToken.lifetime, accToken.id)) + self.db.connection.commit() + return self.getAccessToken(accToken.id) + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) + + def deleteAccessToken(self, accToken): + try: + cursor = self.db.connection.cursor() + cursor.execute("delete from session where id={}".format(accToken.id)) + self.db.connection.commit() + except Exception as err: + traceback.print_exc() + self.db.connection.rollback() + raise DatabaseExecption("Something went worng with Datatabase: {}".format(err)) \ No newline at end of file diff --git a/geruecht/controller/mainController/mainUserController.py b/geruecht/controller/mainController/mainUserController.py index c0c70aa..a021a11 100644 --- a/geruecht/controller/mainController/mainUserController.py +++ b/geruecht/controller/mainController/mainUserController.py @@ -1,3 +1,5 @@ +from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError + from geruecht.exceptions import UsernameExistLDAP, LDAPExcetpion, PermissionDenied import geruecht.controller.databaseController as dc import geruecht.controller.ldapController as lc @@ -114,22 +116,27 @@ class Base: debug.debug("user is {{ {} }}".format(user)) return user - def modifyUser(self, user, ldap_conn, attributes): - debug.info("modify user {{ {} }} with attributes {{ {} }} with ldap_conn {{ {} }}".format( - user, attributes, ldap_conn)) + def modifyUser(self, user, attributes, password): + debug.info("modify user {{ {} }} with attributes {{ {} }}".format( + user, attributes)) + try: - 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 + ldap_conn = ldap.bind(user, 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) @@ -139,6 +146,10 @@ class Base: 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) @@ -153,8 +164,7 @@ class Base: debug.debug("user is {{ {} }}".format(user)) user.password = password ldap.login(username, password) - ldap_conn = ldap.bind(user, password) - return user, ldap_conn + return user except PermissionDenied as err: debug.debug("permission is denied", exc_info=True) raise err \ No newline at end of file diff --git a/geruecht/model/accessToken.py b/geruecht/model/accessToken.py index 0e7746c..91586c9 100644 --- a/geruecht/model/accessToken.py +++ b/geruecht/model/accessToken.py @@ -15,9 +15,8 @@ class AccessToken(): timestamp = None user = None token = None - ldap_conn = None - def __init__(self, user, token, ldap_conn, lifetime, timestamp=datetime.now()): + def __init__(self, id, user, token, lifetime, timestamp=datetime.now(), browser=None, platform=None): """ Initialize Class AccessToken No more to say. @@ -28,12 +27,14 @@ class AccessToken(): timestamp: Default current time, but can set to an other datetime-Object. """ debug.debug("init accesstoken") + self.id = id self.user = user self.timestamp = timestamp self.lifetime = lifetime self.token = token - self.ldap_conn = ldap_conn self.lock_bar = False + self.browser = browser + self.platform = platform debug.debug("accesstoken is {{ {} }}".format(self)) def updateTimestamp(self): @@ -44,6 +45,27 @@ class AccessToken(): debug.debug("update timestamp from accesstoken {{ {} }}".format(self)) self.timestamp = datetime.now() + def toJSON(self): + """ Create Dic to dump in JSON + + Returns: + A Dic with static Attributes. + """ + dic = { + "id": self.id, + "timestamp": {'year': self.timestamp.year, + 'month': self.timestamp.month, + 'day': self.timestamp.day, + 'hour': self.timestamp.hour, + 'minute': self.timestamp.minute, + 'second': self.timestamp.second + }, + "lifetime": self.lifetime, + "browser": self.browser, + "platform": self.platform + } + return dic + def __eq__(self, token): return True if self.token == token else False diff --git a/geruecht/routes.py b/geruecht/routes.py index a79e402..c8f7810 100644 --- a/geruecht/routes.py +++ b/geruecht/routes.py @@ -132,7 +132,8 @@ def _saveLifeTime(**kwargs): lifetime, accToken)) accToken.lifetime = lifetime debug.info("update accesstoken timestamp") - accToken.updateTimestamp() + accToken = accesTokenController.updateAccessToken(accToken) + accToken = accesTokenController.validateAccessToken(accToken.token, [USER, EXTERN]) retVal = {"value": accToken.lifetime, "group": accToken.user.toJSON()['group']} debug.info( @@ -143,7 +144,6 @@ def _saveLifeTime(**kwargs): "exception in save lifetime for accesstoken.", exc_info=True) return jsonify({"error": str(err)}), 500 - @app.route("/logout", methods=['GET']) @login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True) def _logout(**kwargs): @@ -177,11 +177,11 @@ def _login(): password = data['password'] debug.debug("username is {{ {} }}".format(username)) try: + user_agent = request.user_agent debug.info("search {{ {} }} in database".format(username)) - user, ldap_conn = mainController.loginUser(username, password) + user = mainController.loginUser(username, password) debug.debug("user is {{ {} }}".format(user)) - user.password = password - token = accesTokenController.createAccesToken(user, ldap_conn) + token = accesTokenController.createAccesToken(user, user_agent=user_agent) debug.debug("accesstoken is {{ {} }}".format(token)) debug.info("validate accesstoken") dic = accesTokenController.validateAccessToken( @@ -194,6 +194,6 @@ def _login(): except PermissionDenied as err: debug.warning("permission denied exception in logout", exc_info=True) return jsonify({"error": str(err)}), 401 - except Exception: + except Exception as err: debug.warning("exception in logout.", exc_info=True) return jsonify({"error": "permission denied"}), 401 diff --git a/geruecht/user/routes.py b/geruecht/user/routes.py index e433798..6b5e3c2 100644 --- a/geruecht/user/routes.py +++ b/geruecht/user/routes.py @@ -1,14 +1,17 @@ from flask import Blueprint, request, jsonify from geruecht.decorator import login_required import geruecht.controller.mainController as mc +import geruecht.controller.accesTokenController as ac from geruecht.model import USER from datetime import datetime, time, date from geruecht.exceptions import DayLocked from geruecht.logger import getDebugLogger, getCreditLogger, getJobsLogger +from geruecht.model.accessToken import AccessToken user = Blueprint("user", __name__) mainController = mc.MainController() +accesTokenController = ac.AccesTokenController() debug = getDebugLogger() creditL = getCreditLogger() @@ -66,8 +69,10 @@ def _saveConfig(**kwargs): if 'accToken' in kwargs: accToken = kwargs['accToken'] data = request.get_json() + password = data['acceptedPassword'] + data.pop('acceptedPassword') accToken.user = mainController.modifyUser( - accToken.user, accToken.ldap_conn, data) + accToken.user, data, password) retVal = accToken.user.toJSON() retVal['creditList'] = {credit.year: credit.toJSON() for credit in accToken.user.geruechte} @@ -385,4 +390,24 @@ def _deleteJobRequest(**kwargs): return jsonify(retVal) except Exception as err: debug.debug("exception", exc_info=True) - return jsonify({"error": str(err)}), 500 \ No newline at end of file + return jsonify({"error": str(err)}), 500 + + +@user.route("/user/getAccessTokens", methods=['GET', 'POST']) +@login_required(groups=[USER]) +def _getAccessTokens(**kwargs): + try: + debug.info("/user/getAccessTokens") + if request.method == 'POST': + data = request.get_json() + delAccToken = AccessToken(data['id'], kwargs['accToken'].user, None, None, None) + accesTokenController.deleteAccessToken(delAccToken) + tokens = accesTokenController.getAccessTokensFromUser(kwargs['accToken'].user) + retVal = [] + for token in tokens: + retVal.append(token.toJSON()) + debug.debug("return {{ {} }}".format(retVal)) + return jsonify(retVal) + except Exception as err: + debug.debug("exception", exc_info=True) + return jsonify({"error": str(err)}), 500