Added modules for authentification.

* Added base class for auth plugins
  * Provide plain_auth (using password authentification)
  * Provide module for login and logout handling
This commit is contained in:
Ferdinand Thiessen 2020-08-22 16:47:56 +02:00
parent 187dc40730
commit a000ccfb1c
16 changed files with 256 additions and 664 deletions

View File

@ -19,6 +19,11 @@ with (_modpath/'logging.yml').open(mode='rb') as file:
config = yaml.safe_load(file.read())
dictConfig(config)
import logging
from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: logging.getLogger(__name__))
def create_app():
app = Flask(__name__)
CORS(app)

View File

@ -37,11 +37,6 @@ handlers:
encoding: utf8
loggers:
debug_logger:
level: DEBUG
handlers: [console, debug]
propagate: no
credit_logger:
level: INFO
handlers: [credit]
@ -52,6 +47,9 @@ loggers:
handlers: [jobs]
propagate: no
werkzeug:
level: WARNING
root:
level: INFO
handlers: [console, debug]
level: DEBUG
handlers: [console, debug]

View File

@ -0,0 +1,29 @@
class Auth():
def login(self, user, pw):
"""
user User class containing at least the uid
pw given password
HAS TO BE IMPLEMENTED!
should return False if not found or invalid credentials
should return True if success
"""
return False
def updateUser(self, user):
"""
user User class
If backend is using external data, then update this user instance with external data
"""
pass
def modifyUser(self, user):
"""
user User class
If backend is using (writeable) external data, then update the external database with the user provided.
"""
pass

View File

@ -0,0 +1,77 @@
#############################################
# Plugin: Auth #
# Functionality: Allow management of #
# authentification, login, logout, etc #
#############################################
from flask import Blueprint, current_app, request, jsonify
from werkzeug.local import LocalProxy
from flaschengeist.system.decorator import login_required
from flaschengeist.system.exceptions import PermissionDenied
from flaschengeist.system.controller import mainController as mc
import flaschengeist.system.controller.accesTokenController as ac
logger = LocalProxy(lambda: current_app.logger)
accesTokenController = LocalProxy(lambda: ac.AccesTokenController())
auth_bp = Blueprint('auth', __name__)
def register():
return auth_bp
############################################
## Routes ##
############################################
@auth_bp.route("/logout", methods=['GET'])
@login_required()
def _logout(**kwargs):
try:
logger.debug("logout user")
accToken = kwargs['accToken']
logger.debug("accesstoken is {{ {} }}".format(accToken))
logger.debug("delete accesstoken")
accesTokenController.deleteAccessToken(accToken)
logger.info("return ok logout user")
return jsonify({"ok": "ok"})
except Exception as err:
logger.warning("exception in logout user.", exc_info=True)
return jsonify({"error": str(err)}), 500
@auth_bp.route("/login", methods=['POST'])
def _login():
""" Login User
Nothing to say.
Login in User and create an AccessToken for the User.
Returns:
A JSON-File with createt Token or Errors
"""
logger.debug("Start log in.")
data = request.get_json()
logger.info(request)
username = data['username']
password = data['password']
logger.debug("username is {{ {} }}".format(username))
try:
logger.debug("search {{ {} }} in database".format(username))
mainController = mc.MainController()
user = mainController.loginUser(username, password)
logger.debug("user is {{ {} }}".format(user))
token = accesTokenController.createAccesToken(user, user_agent=request.user_agent)
logger.debug("accesstoken is {{ {} }}".format(token))
logger.debug("validate accesstoken")
dic = user.toJSON()
dic["token"] = token
logger.info("User {{ {} }} success login.".format(username))
logger.debug("return login {{ {} }}".format(dic))
return jsonify(dic)
except PermissionDenied as err:
logger.debug("permission denied exception in login", exc_info=True)
return jsonify({"error": str(err)}), 401
except Exception as err:
logger.error("exception in login.", exc_info=True)
return jsonify({"error": "permission denied"}), 401

View File

@ -0,0 +1,24 @@
import hashlib, binascii, os
import flaschengeist.modules as modules
class AuthPlain(modules.Auth):
def login(self, user, password):
if not user:
return False
if 'password' in user.attributes:
return self.__verify_password(user.attributes['password'].value, password)
return False
def __hash_password(self, password):
salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
pwdhash = hashlib.pbkdf2_hmac('sha3-512', password.encode('utf-8'), salt, 100000)
pwdhash = binascii.hexlify(pwdhash)
return (salt + pwdhash).decode('ascii')
def __verify_password(self, stored_password, provided_password):
salt = stored_password[:64]
stored_password = stored_password[64:]
pwdhash = hashlib.pbkdf2_hmac('sha3-512', provided_password.encode('utf-8'),
salt.encode('ascii'), 100000)
pwdhash = binascii.hexlify(pwdhash).decode('ascii')
return pwdhash == stored_password

View File

@ -1,56 +0,0 @@
#######################################
# Plugin: Users #
# Functionality: Allow management #
# of users, login, logout, etc #
#######################################
from flask import Blueprint
from flaschengeist.app import app
def register():
return Blueprint('user', __name__)
#######################################
## Routes ##
#######################################
#dummy
@app.route("/")
def _dummy():
return 'Noch funktioniert hier mal überhaupt nichts!'
@app.route("/login", methods=['POST'])
def _login():
""" Login User
Nothing to say.
Login in User and create an AccessToken for the User.
Returns:
A JSON-File with createt Token or Errors
"""
debug.info("Start log in.")
data = request.get_json()
username = data['username']
password = data['password']
debug.debug("username is {{ {} }}".format(username))
try:
user_agent = request.user_agent
debug.info("search {{ {} }} in database".format(username))
user = mainController.loginUser(username, password)
debug.debug("user is {{ {} }}".format(user))
token = accesTokenController.createAccesToken(user, user_agent=user_agent)
debug.debug("accesstoken is {{ {} }}".format(token))
debug.info("validate accesstoken")
dic = accesTokenController.validateAccessToken(
token, [USER, EXTERN]).user.toJSON()
dic["token"] = token
dic["accessToken"] = token
debug.info("User {{ {} }} success login.".format(username))
debug.info("return login {{ {} }}".format(dic))
return jsonify(dic)
except PermissionDenied as err:
debug.warning("permission denied exception in logout", exc_info=True)
return jsonify({"error": str(err)}), 401
except Exception as err:
debug.warning("exception in logout.", exc_info=True)
return jsonify({"error": "permission denied"}), 401

View File

@ -1,216 +0,0 @@
from geruecht import app
from geruecht.logger import getDebugLogger
from geruecht.decorator import login_required
from geruecht.exceptions import PermissionDenied
import geruecht.controller.accesTokenController as ac
import geruecht.controller.mainController as mc
from geruecht.model import MONEY, BAR, USER, GASTRO, VORSTAND, EXTERN
from flask import request, jsonify
accesTokenController = ac.AccesTokenController()
mainController = mc.MainController()
debug = getDebugLogger()
@app.route("/valid", methods=['POST'])
@login_required(bar=True)
def _valid(**kwargs):
debug.info('/valid')
try:
accToken = kwargs['accToken']
data = request.get_json()
mainController.validateUser(accToken.user.uid, data['password'])
debug.debug('return {{ "ok": "ok" }}')
return jsonify({"ok": "ok"})
except Exception as err:
debug.warning("exception in valide.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route("/pricelist", methods=['GET'])
def _getPricelist():
try:
debug.info("get pricelist")
retVal = mainController.getPricelist()
debug.info("return pricelist {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.warning("exception in get pricelist.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route('/drinkTypes', methods=['GET'])
def getTypes():
try:
debug.info("get drinktypes")
retVal = mainController.getAllDrinkTypes()
debug.info("return drinktypes {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.warning("exception in get drinktypes.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route('/getAllStatus', methods=['GET'])
@login_required(groups=[USER, MONEY, GASTRO, BAR, VORSTAND], bar=True)
def _getAllStatus(**kwargs):
try:
debug.info("get all status for users")
retVal = mainController.getAllStatus()
debug.info("return all status for users {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.warning("exception in get all status for users.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route('/getStatus', methods=['POST'])
@login_required(groups=[USER, MONEY, GASTRO, BAR, VORSTAND], bar=True)
def _getStatus(**kwargs):
try:
debug.info("get status from user")
data = request.get_json()
name = data['name']
debug.info("get status from user {{ {} }}".format(name))
retVal = mainController.getStatus(name)
debug.info(
"return status from user {{ {} }} : {{ {} }}".format(name, retVal))
return jsonify(retVal)
except Exception as err:
debug.warning("exception in get status from user.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route('/getUsers', methods=['GET'])
@login_required(groups=[USER], bar=True)
def _getUsers(**kwargs):
try:
extern = True
if 'extern' in request.args:
extern = not bool(int(request.args['extern']))
debug.info("get all users from database")
users = mainController.getAllUsersfromDB(extern=extern)
debug.debug("users are {{ {} }}".format(users))
retVal = [user.toJSON() for user in users]
debug.info("return all users from database {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.warning(
"exception in get all users from database.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route("/getLifeTime", methods=['GET'])
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
def _getLifeTime(**kwargs):
try:
debug.info("get lifetime of accesstoken")
if 'accToken' in kwargs:
accToken = kwargs['accToken']
debug.debug("accessToken is {{ {} }}".format(accToken))
retVal = {"value": accToken.lifetime,
"group": accToken.user.toJSON()['group'],
"lock_bar": accToken.lock_bar}
debug.info(
"return get lifetime from accesstoken {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.info("exception in get lifetime of accesstoken.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route("/saveLifeTime", methods=['POST'])
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
def _saveLifeTime(**kwargs):
try:
debug.info("save lifetime for accessToken")
if 'accToken' in kwargs:
accToken = kwargs['accToken']
debug.debug("accessToken is {{ {} }}".format(accToken))
data = request.get_json()
lifetime = data['value']
debug.debug("lifetime is {{ {} }}".format(lifetime))
debug.info("set lifetime {{ {} }} to accesstoken {{ {} }}".format(
lifetime, accToken))
accToken.lifetime = lifetime
debug.info("update accesstoken timestamp")
accToken = accesTokenController.updateAccessToken(accToken)
accToken = accesTokenController.validateAccessToken(accToken.token, [USER, EXTERN])
retVal = {"value": accToken.lifetime,
"group": accToken.user.toJSON()['group']}
debug.info(
"return save lifetime for accessToken {{ {} }}".format(retVal))
return jsonify(retVal)
except Exception as err:
debug.warning(
"exception in save lifetime for accesstoken.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route("/passwordReset", methods=['POST'])
def _passwordReset():
try:
debug.info('password reset')
data = request.get_json()
mail = mainController.resetPassword(data)
index = mail.find('@')
for i in range(index):
if i == 0:
continue
mail = mail.replace(mail[i], "*", 1)
return jsonify({"ok": "ok", "mail": mail})
except Exception as err:
debug.warning("excetpion in password reset", exc_info=True)
return jsonify({"error": str(err)}), 409
@app.route("/logout", methods=['GET'])
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
def _logout(**kwargs):
try:
debug.info("logout user")
if 'accToken' in kwargs:
accToken = kwargs['accToken']
debug.debug("accesstoken is {{ {} }}".format(accToken))
debug.info("delete accesstoken")
accesTokenController.deleteAccessToken(accToken)
debug.info("return ok logout user")
return jsonify({"ok": "ok"})
except Exception as err:
debug.warning("exception in logout user.", exc_info=True)
return jsonify({"error": str(err)}), 500
@app.route("/login", methods=['POST'])
def _login():
""" Login User
Nothing to say.
Login in User and create an AccessToken for the User.
Returns:
A JSON-File with createt Token or Errors
"""
debug.info("Start log in.")
data = request.get_json()
username = data['username']
password = data['password']
debug.debug("username is {{ {} }}".format(username))
try:
user_agent = request.user_agent
debug.info("search {{ {} }} in database".format(username))
user = mainController.loginUser(username, password)
debug.debug("user is {{ {} }}".format(user))
token = accesTokenController.createAccesToken(user, user_agent=user_agent)
debug.debug("accesstoken is {{ {} }}".format(token))
debug.info("validate accesstoken")
dic = accesTokenController.validateAccessToken(
token, [USER, EXTERN]).user.toJSON()
dic["token"] = token
dic["accessToken"] = token
debug.info("User {{ {} }} success login.".format(username))
debug.info("return login {{ {} }}".format(dic))
return jsonify(dic)
except PermissionDenied as err:
debug.warning("permission denied exception in logout", exc_info=True)
return jsonify({"error": str(err)}), 401
except Exception as err:
debug.warning("exception in logout.", exc_info=True)
return jsonify({"error": "permission denied"}), 401

View File

@ -1,244 +0,0 @@
from geruecht.logger import getDebugLogger
from geruecht.model.creditList import CreditList, create_empty_data
from datetime import datetime
debug = getDebugLogger()
class User():
""" Database Object for User
Table for all safed User
Attributes:
id: Id in Database as Primary Key.
userID: ID for the User maybe to Link?
username: Username of the User to Login
firstname: Firstname of the User
Lastname: Lastname of the User
group: Which group is the User? moneymaster, gastro, user or bar?
password: salted hashed password for the User.
"""
def __init__(self, data):
debug.info("init user")
if 'id' in data:
self.id = int(data['id'])
self.uid = data['uid']
self.dn = data['dn']
self.firstname = data['firstname']
self.lastname = data['lastname']
self.group = data['gruppe']
self.last_seen = None
if 'last_seen' in data:
self.last_seen = data['last_seen']
if 'statusgroup' in data:
self.statusgroup = data['statusgroup']
else:
self.statusgroup = None
if 'voting' in data:
self.voting = data['voting']
else:
self.voting = None
if 'mail' in data:
self.mail = data['mail']
else:
self.mail = ''
if 'lockLimit' in data:
self.limit = int(data['lockLimit'])
else:
self.limit = 4200
if 'locked' in data:
self.locked = bool(data['locked'])
else:
self.locked = False
if 'autoLock' in data:
self.autoLock = bool(data['autoLock'])
else:
self.autoLock = True
if type(data['gruppe']) == list:
self.group = data['gruppe']
elif type(data['gruppe']) == str:
self.group = data['gruppe'].split(',')
if 'creditLists' in data:
self.geruechte = data['creditLists']
if 'workgroups' in data:
self.workgroups = data['workgroups']
else:
self.workgroups = None
self.password = ''
debug.debug("user is {{ {} }}".format(self))
def updateData(self, data):
debug.info("update data of user")
if 'dn' in data:
self.dn = data['dn']
if 'firstname' in data:
self.firstname = data['firstname']
if 'lastname' in data:
self.lastname = data['lastname']
if 'gruppe' in data:
self.group = data['gruppe']
if 'lockLimit' in data:
self.limit = int(data['lockLimit'])
if 'locked' in data:
self.locked = bool(data['locked'])
if 'autoLock' in data:
self.autoLock = bool(data['autoLock'])
if 'mail' in data:
self.mail = data['mail']
if 'statusgorup' in data:
self.statusgroup = data['statusgroup']
if 'voting' in data:
self.voting = data['voting']
if 'workgroups' in data:
self.workgroups = data['workgroups']
else:
self.workgroups = None
def initGeruechte(self, creditLists):
if type(creditLists) == list:
self.geruechte = creditLists
def createGeruecht(self, amount=0, year=datetime.now().year):
""" Create Geruecht
This function create a geruecht for the user for an year.
By default is amount zero and year the actual year.
Args:
amount: is the last_schulden of the geruecht
year: is the year of the geruecht
Returns:
the created geruecht
"""
debug.info("create creditlist for user {{ {} }} in year {{ {} }}".format(self, year))
data = create_empty_data()
data['user_id'] = self.id
data['last_schulden'] = amount
data['year_date'] = year
credit = CreditList(data)
self.geruechte.append(credit)
debug.debug("creditlist is {{ {} }}".format(credit))
return credit
def getGeruecht(self, year=datetime.now().year):
""" Get Geruecht
This function returns the geruecht of an year.
By default is the year the actual year.
Args:
year: the year of the geruecht
Returns:
the geruecht of the year
"""
debug.info("get creditlist from user on year {{ {} }}".format(year))
for geruecht in self.geruechte:
if geruecht.year == year:
debug.debug("creditlist is {{ {} }} for user {{ {} }}".format(geruecht, self))
return geruecht
debug.debug("no creditlist found for user {{ {} }}".format(self))
geruecht = self.createGeruecht(year=year)
return self.getGeruecht(year=year)
def addAmount(self, amount, year=datetime.now().year, month=datetime.now().month):
""" Add Amount
This function add an amount to a geruecht with an spezified year and month to the user.
By default the year is the actual year.
By default the month is the actual month.
Args:
year: year of the geruecht
month: month for the amount
Returns:
double (credit, amount)
"""
debug.info("add amount to user {{ {} }} in year {{ {} }} and month {{ {} }}".format(self, year, month))
geruecht = self.getGeruecht(year=year)
retVal = geruecht.addAmount(amount, month=month)
return retVal
def addCredit(self, credit, year=datetime.now().year, month=datetime.now().month):
""" Add Credit
This function add an credit to a geruecht with an spezified year and month to the user.
By default the year is the actual year.
By default the month is the actual month.
Args:
year: year of the geruecht
month: month for the amount
Returns:
double (credit, amount)
"""
debug.info("add credit to user {{ {} }} in year {{ {} }} and month {{ {} }}".format(self, year, month))
geruecht = self.getGeruecht(year=year)
retVal = geruecht.addCredit(credit, month=month)
return retVal
def updateGeruecht(self):
""" Update list of geruechte
This function iterate through the geruechte, which sorted by year and update the last_schulden of the geruecht.
"""
debug.info("update all creditlists ")
self.geruechte.sort(key=self.sortYear)
for index, geruecht in enumerate(self.geruechte):
if index == 0 or index == len(self.geruechte) - 1:
geruecht.last_schulden = 0
if index != 0:
geruecht.last_schulden = (self.geruechte[index - 1].getSchulden() * -1)
return self.geruechte
def sortYear(self, geruecht):
""" Sort Year
This function is only an helperfunction to sort the list of geruechte by years.
It only returns the year of the geruecht.
Args:
geruecht: geruecht which year you want
Returns:
int year of the geruecht
"""
return geruecht.year
def toJSON(self):
""" Create Dic to dump in JSON
Returns:
A Dic with static Attributes.
"""
dic = {
"id": self.id,
"userId": self.uid,
"uid": self.uid,
"dn": self.dn,
"firstname": self.firstname,
"lastname": self.lastname,
"group": self.group,
"username": self.uid,
"locked": self.locked,
"autoLock": self.autoLock,
"limit": self.limit,
"mail": self.mail,
"statusgroup": self.statusgroup,
"voting": self.voting,
"workgroups": self.workgroups
}
return dic
def __repr__(self):
return "User({}, {}, {})".format(self.uid, self.dn, self.group)

View File

@ -1,12 +1,8 @@
from ..logger import getDebugLogger
from ..configparser import ConifgParser
from flaschengeist import _modpath
import os
config = ConifgParser(_modpath/'config.yml')
LOGGER = getDebugLogger()
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):

View File

@ -1,17 +1,13 @@
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 ..models.accessToken import AccessToken
from flaschengeist.system.database import db
from datetime import datetime, timedelta
import hashlib
import secrets
from . import Singleton
from geruecht.logger import getDebugLogger
from flask import Blueprint, request, jsonify
import logging
debug = getDebugLogger()
mainController = mc.MainController()
db = dc.DatabaseController()
logger = logging.getLogger("flaschenpost")
class AccesTokenController(metaclass=Singleton):
""" Control all createt AccesToken
@ -30,22 +26,8 @@ class AccesTokenController(metaclass=Singleton):
Initialize Thread and set tokenList empty.
"""
debug.info("init accesstoken controller")
self.lifetime = gc.accConfig
def checkBar(self, user):
debug.info("check if user {{ {} }} is baruser".format(user))
if (mainController.checkBarUser(user)):
if BAR not in user.group:
debug.debug("append bar to user {{ {} }}".format(user))
user.group.append(BAR)
return True
else:
while BAR in user.group:
debug.debug("delete bar from user {{ {} }}".format(user))
user.group.remove(BAR)
return False
debug.debug("user {{ {} }} groups are {{ {} }}".format(user, user.group))
logger.debug("init accesstoken controller")
self.lifetime = lifetime
def validateAccessToken(self, token, group):
""" Verify Accestoken
@ -59,27 +41,27 @@ class AccesTokenController(metaclass=Singleton):
Returns:
An the AccesToken for this given Token or False.
"""
debug.info("check token {{ {} }} is valid")
for accToken in db.getAccessTokens():
debug.debug("accesstoken is {}".format(accToken))
logger.debug("check token {{ {} }} is valid".format(token))
for accToken in AccessToken.query.filter_by(token=token):
endTime = accToken.timestamp + timedelta(seconds=accToken.lifetime)
now = datetime.now()
debug.debug("now is {{ {} }}, endtime is {{ {} }}".format(now, endTime))
now = datetime.utcnow()
logger.debug("now is {{ {} }}, endtime is {{ {} }}".format(now, endTime))
if now <= endTime:
debug.debug("check if token {{ {} }} is same as {{ {} }}".format(token, accToken))
logger.debug("check if token {{ {} }} is same as {{ {} }}".format(token, accToken))
if accToken == token:
if not self.checkBar(accToken.user):
accToken.lock_bar = False
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
# if not self.checkBar(accToken.user):
# accToken.lock_bar = False
# logger.debug("check if accestoken {{ {} }} has group {{ {} }}".format(accToken, group))
# if self.isSameGroup(accToken, group):
accToken.updateTimestamp()
db.session.commit()
# logger.debug("found accesstoken {{ {} }} with token: {{ {} }} and group: {{ {} }}".format(accToken, token, group))
return accToken
else:
debug.debug("accesstoken is {{ {} }} out of date".format(accToken))
db.deleteAccessToken(accToken)
debug.debug("no valid accesstoken with token: {{ {} }} and group: {{ {} }}".format(token, group))
logger.debug("accesstoken is {{ {} }} out of date".format(accToken))
db.session.delete(accToken)
db.session.commit()
logger.debug("no valid accesstoken with token: {{ {} }} and group: {{ {} }}".format(token, group))
return False
def createAccesToken(self, user, user_agent=None):
@ -93,12 +75,13 @@ class AccesTokenController(metaclass=Singleton):
Returns:
A created Token for User
"""
debug.info("creat accesstoken")
now = datetime.ctime(datetime.now())
token = hashlib.md5((now + user.dn).encode('utf-8')).hexdigest()
self.checkBar(user)
accToken = db.createAccessToken(user, token, self.lifetime, datetime.now(), lock_bar=False, user_agent=user_agent)
debug.debug("accesstoken is {{ {} }}".format(accToken))
logger.debug("creat accesstoken")
token = secrets.token_hex(16)
accToken = AccessToken(token=token, user=user, lifetime=self.lifetime, browser=user_agent.browser, platform=user_agent.platform)
db.session.add(accToken)
db.session.commit()
logger.debug("accesstoken is {{ {} }}".format(accToken))
return token
def isSameGroup(self, accToken, groups):
@ -122,7 +105,9 @@ class AccesTokenController(metaclass=Singleton):
return db.getAccessTokensFromUser(user)
def deleteAccessToken(self, accToken):
db.deleteAccessToken(accToken)
db.session.delete(accToken)
db.session.commit()
#AccessToken.query.filter_by(token=accToken).delete()
def updateAccessToken(self, accToken):
accToken.updateTimestamp()

View File

@ -1,44 +1,37 @@
from .. import Singleton, mailConfig
import geruecht.controller.databaseController as dc
import geruecht.controller.ldapController as lc
import geruecht.controller.emailController as ec
from geruecht.model.user import User
from ...models.user import User
from datetime import datetime, timedelta
from geruecht.logger import getDebugLogger
from ..mainController import mainJobKindController, mainCreditListController, mainPricelistController, mainUserController, mainWorkerController, mainWorkgroupController, mainJobInviteController, mainJobRequestController, mainRegistrationController, mainPasswordReset
from . import mainUserController
from ...database import db
from flask import current_app
from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: current_app.logger)
db = dc.DatabaseController()
ldap = lc.LDAPController()
emailController = ec.EmailController()
debug = getDebugLogger()
class MainController(mainJobKindController.Base,
mainCreditListController.Base,
mainPricelistController.Base,
class MainController(#mainJobKindController.Base,
#mainCreditListController.Base,
#mainPricelistController.Base,
mainUserController.Base,
mainWorkerController.Base,
mainWorkgroupController.Base,
mainJobInviteController.Base,
mainJobRequestController.Base,
mainRegistrationController.Base,
mainPasswordReset.Base,
#mainWorkerController.Base,
#mainWorkgroupController.Base,
#mainJobInviteController.Base,
#mainJobRequestController.Base,
#mainRegistrationController.Base,
#mainPasswordReset.Base,
metaclass=Singleton):
def __init__(self):
debug.debug("init UserController")
logger.debug("init UserController")
pass
def setLockedDay(self, date, locked, hard=False):
debug.info(
logger.info(
"set day locked on {{ {} }} with state {{ {} }}".format(date, locked))
retVal = db.setLockedDay(date.date(), locked, hard)
debug.debug("seted day locked is {{ {} }}".format(retVal))
logger.debug("seted day locked is {{ {} }}".format(retVal))
return retVal
def getLockedDays(self, from_date, to_date):
debug.info("get locked days from {{ {} }} to {{ {} }}".format(
logger.info("get locked days from {{ {} }} to {{ {} }}".format(
from_date.date(), to_date.date()))
oneDay = timedelta(1)
delta = to_date.date() - from_date.date()
@ -48,11 +41,11 @@ class MainController(mainJobKindController.Base,
startdate += oneDay
lockday = self.getLockedDay(startdate)
retVal.append(lockday)
debug.debug("lock days are {{ {} }}".format(retVal))
logger.debug("lock days are {{ {} }}".format(retVal))
return retVal
def getLockedDaysFromList(self, date_list):
debug.info("get locked days from list {{ {} }}".format(date_list))
logger.info("get locked days from list {{ {} }}".format(date_list))
retVal = []
for on_date in date_list:
day = datetime(on_date['on_date']['year'], on_date['on_date']['month'], on_date['on_date']['day'], 12)
@ -60,22 +53,22 @@ class MainController(mainJobKindController.Base,
return retVal
def getLockedDay(self, date):
debug.info("get locked day on {{ {} }}".format(date))
logger.info("get locked day on {{ {} }}".format(date))
now = datetime.now()
debug.debug("now is {{ {} }}".format(now))
logger.debug("now is {{ {} }}".format(now))
oldMonth = False
debug.debug("check if date old month or current month")
logger.debug("check if date old month or current month")
for i in range(1, 8):
if datetime(now.year, now.month, i).weekday() == 2:
if now.day < i:
oldMonth = True
break
debug.debug("oldMonth is {{ {} }}".format(oldMonth))
logger.debug("oldMonth is {{ {} }}".format(oldMonth))
lockedYear = now.year
lockedMonth = now.month if now.month < now.month else now.month - \
1 if oldMonth else now.month
endDay = 1
debug.debug("calculate end day of month")
logger.debug("calculate end day of month")
lockedYear = lockedYear if lockedMonth != 12 else (lockedYear + 1)
lockedMonth = (lockedMonth + 1) if lockedMonth != 12 else 1
for i in range(1, 8):
@ -86,33 +79,33 @@ class MainController(mainJobKindController.Base,
monthLockedEndDate = datetime(
lockedYear, lockedMonth, endDay) - timedelta(1)
debug.debug("get lock day from database")
logger.debug("get lock day from database")
retVal = db.getLockedDay(date.date())
if not retVal:
debug.debug(
logger.debug(
"lock day not exists, retVal is {{ {} }}".format(retVal))
if date.date() <= monthLockedEndDate.date():
debug.debug("lock day {{ {} }}".format(date.date()))
logger.debug("lock day {{ {} }}".format(date.date()))
self.setLockedDay(date, True)
retVal = db.getLockedDay(date.date())
else:
retVal = {"daydate": date.date(), "locked": False}
debug.debug("locked day is {{ {} }}".format(retVal))
logger.debug("locked day is {{ {} }}".format(retVal))
return retVal
def __updateDataFromLDAP(self, user):
debug.info("update data from ldap for user {{ {} }}".format(user))
logger.info("update data from ldap for user {{ {} }}".format(user))
groups = ldap.getGroup(user.uid)
debug.debug("ldap gorups are {{ {} }}".format(groups))
logger.debug("ldap gorups are {{ {} }}".format(groups))
user_data = ldap.getUserData(user.uid)
debug.debug("ldap data is {{ {} }}".format(user_data))
logger.debug("ldap data is {{ {} }}".format(user_data))
user_data['gruppe'] = groups
user_data['group'] = groups
user.updateData(user_data)
db.updateUser(user)
def checkBarUser(self, user):
debug.info("check if user {{ {} }} is baruser")
logger.info("check if user {{ {} }} is baruser")
date = datetime.now()
zero = date.replace(hour=0, minute=0, second=0, microsecond=0)
end = zero + timedelta(hours=12)
@ -121,22 +114,22 @@ class MainController(mainJobKindController.Base,
if date > zero and end > date:
startdatetime = startdatetime - timedelta(days=1)
enddatetime = startdatetime + timedelta(days=1)
debug.debug("startdatetime is {{ {} }} and enddatetime is {{ {} }}".format(
logger.debug("startdatetime is {{ {} }} and enddatetime is {{ {} }}".format(
startdatetime, end))
result = False
if date >= startdatetime and date < enddatetime:
result = db.getWorker(user, startdatetime)
debug.debug("worker is {{ {} }}".format(result))
logger.debug("worker is {{ {} }}".format(result))
return True if result else False
def sendMail(self, username):
debug.info("send mail to user {{ {} }}".format(username))
logger.info("send mail to user {{ {} }}".format(username))
if type(username) == User:
user = username
if type(username) == str:
user = db.getUser(username)
retVal = emailController.sendMail(user)
debug.debug("send mail is {{ {} }}".format(retVal))
logger.debug("send mail is {{ {} }}".format(retVal))
return retVal
def sendAllMail(self):

View File

@ -1,14 +1,10 @@
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
from flaschengeist.system.exceptions import UsernameExistLDAP, LDAPExcetpion, PermissionDenied
from flaschengeist.system.models.user import User
from flaschengeist.system.database import db
from geruecht.exceptions import UsernameExistLDAP, LDAPExcetpion, PermissionDenied
import geruecht.controller.databaseController as dc
import geruecht.controller.ldapController as lc
from geruecht.logger import getDebugLogger
from geruecht.model.user import User
db = dc.DatabaseController()
ldap = lc.LDAPController()
debug = getDebugLogger()
from flask import Blueprint, current_app
from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: current_app.logger)
class Base:
def getAllStatus(self):
@ -167,13 +163,14 @@ class Base:
ldap.login(username, password)
def loginUser(self, username, password):
debug.info("login user {{ {} }}".format(username))
try:
user = self.getUser(username)
debug.debug("user is {{ {} }}".format(user))
user.password = password
ldap.login(username, password)
return user
except PermissionDenied as err:
debug.debug("permission is denied", exc_info=True)
raise err
logger.info("login user {{ {} }}".format(username))
user = User.query.filter_by(uid=username).first()
if user is None:
user = User(uid=username)
for backend in current_app.config['FG_AUTH_BACKENDS']:
b = backend()
if b.login(user, password):
db.session.add(user)
db.session.commit()
return user
raise PermissionDenied()

View File

@ -1,35 +1,29 @@
from functools import wraps
from flask import current_app
from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: current_app.logger)
from flask import current_app, request, jsonify
from flaschengeist import logger
def login_required(**kwargs):
import geruecht.controller.accesTokenController as ac
from geruecht.model import BAR, USER, MONEY, GASTRO, VORSTAND, EXTERN
from flask import request, jsonify
accessController = ac.AccesTokenController()
groups = [USER, BAR, GASTRO, MONEY, VORSTAND, EXTERN]
bar = False
if "groups" in kwargs:
groups = kwargs["groups"]
if "bar" in kwargs:
bar = kwargs["bar"]
logger.debug("groups are {{ {} }}".format(groups))
from .controller.accesTokenController import AccesTokenController
accessController = AccesTokenController()
#if "groups" in kwargs:
# groups = kwargs["groups"]
#if "bar" in kwargs:
# bar = kwargs["bar"]
#logger.debug("groups are {{ {} }}".format(groups))
def real_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
token = request.headers.get('Token')
logger.debug("token is {{ {} }}".format(token))
accToken = accessController.validateAccessToken(token, groups)
accToken = accessController.validateAccessToken(token, None)
logger.debug("accToken is {{ {} }}".format(accToken))
kwargs['accToken'] = accToken
if accToken:
logger.debug("token {{ {} }} is valid".format(token))
if accToken.lock_bar and not bar:
return jsonify({"error": "error",
"message": "permission forbidden"}), 403
# if accToken.lock_bar and not bar:
# return jsonify({"error": "error",
# "message": "permission forbidden"}), 403
return func(*args, **kwargs)
else:
logger.warning("token {{ {} }} is not valid".format(token))

View File

@ -52,7 +52,7 @@ class AccessToken(db.Model):
return dic
def __eq__(self, token):
return True if self.token == token else False
return self.token == token
def __sub__(self, other):
return other - self.timestamp

View File

@ -48,6 +48,16 @@ class User(db.Model):
if 'displayname' in data:
self.displayname = data['displayname']
def toJSON(self):
return {
"uid": self.uid,
"displayname": self.displayname,
"firstname": self.firstname,
"lastname": self.lastname,
"mail": self.mail,
"groups": self.groups
}
class UserAttribute(db.Model):
__tablename__ = 'userAttribute'

View File

@ -13,7 +13,7 @@ setup(
install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", "flask_ldapconn", "flask_cors"],
entry_points = {
'flaschengeist.plugin': [
'user = flaschengeist.modules.user:register'
'auth = flaschengeist.modules.auth:register'
],
'flaschengeist.auth': [
'plain_auth = flaschengeist.modules.auth_plain:AuthPlain'