Merge branch 'feature/accessToken' into develop

This commit is contained in:
Tim Gröger 2020-06-05 01:25:05 +02:00
commit a1098713ca
7 changed files with 186 additions and 39 deletions

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
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