mysql adapter and ldap adapter

start adapetr for mysql not sqllite
authenfication with ldap

problem.. ldap and db is initialize in __init__.py
when you initialize db, you initialize User and that requires ldap from __init__.py. But ldap is not initialize.
if you initialize ldap, you initialize User and that requires db from __init__.py. But db is not initialize.
This commit is contained in:
Tim Gröger 2019-12-19 08:12:29 +01:00
parent cd0def0c1b
commit e8fc6c64b9
7 changed files with 208 additions and 47 deletions

View File

@ -8,6 +8,11 @@ import logging
from logging.handlers import WatchedFileHandler from logging.handlers import WatchedFileHandler
import sys import sys
MONEY = "moneymaster"
GASTRO = "gastro"
USER = "user"
BAR = "bar"
FORMATTER = logging.Formatter("%(asctime)s%(name)s%(levelname)s%(message)s") FORMATTER = logging.Formatter("%(asctime)s%(name)s%(levelname)s%(message)s")
logFileHandler = WatchedFileHandler("testlog.log") logFileHandler = WatchedFileHandler("testlog.log")
@ -29,6 +34,18 @@ def getLogger(logger_name):
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
LOGGER.info("Initialize App") LOGGER.info("Initialize App")
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
from .controller.databaseController import DatabaseController
db = DatabaseController()
from .controller.ldapController import LDAPController
ldapController = LDAPController()
from flask import Flask from flask import Flask
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
@ -41,7 +58,7 @@ app = Flask(__name__)
CORS(app) CORS(app)
# app.config['SECRET_KEY'] = '0a657b97ef546da90b2db91862ad4e29' # app.config['SECRET_KEY'] = '0a657b97ef546da90b2db91862ad4e29'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app) #db = SQLAlchemy(app)
bcrypt = Bcrypt(app) bcrypt = Bcrypt(app)
accesTokenController = AccesTokenController("GERUECHT") accesTokenController = AccesTokenController("GERUECHT")
accesTokenController.start() accesTokenController.start()
@ -49,16 +66,13 @@ accesTokenController.start()
# login_manager.login_view = 'login' # login_manager.login_view = 'login'
# login_manager.login_message_category = 'info' # login_manager.login_message_category = 'info'
MONEY = "moneymaster"
GASTRO = "gastro"
USER = "user"
BAR = "bar"
from geruecht import routes from geruecht import routes
from geruecht.baruser.routes import baruser #from geruecht.baruser.routes import baruser
from geruecht.finanzer.routes import finanzer #from geruecht.finanzer.routes import finanzer
LOGGER.info("Registrate bluebrints") #LOGGER.info("Registrate bluebrints")
app.register_blueprint(baruser) #app.register_blueprint(baruser)
app.register_blueprint(finanzer) #app.register_blueprint(finanzer)

View File

@ -6,8 +6,9 @@ from threading import Thread
import hashlib import hashlib
import logging import logging
from logging.handlers import WatchedFileHandler from logging.handlers import WatchedFileHandler
from geruecht import Singleton
class AccesTokenController(Thread): class AccesTokenController(Thread, metaclass=Singleton):
""" Control all createt AccesToken """ Control all createt AccesToken
This Class create, delete, find and manage AccesToken. This Class create, delete, find and manage AccesToken.
@ -16,12 +17,6 @@ class AccesTokenController(Thread):
tokenList: List of currents AccessToken tokenList: List of currents AccessToken
lifetime: Variable for the Lifetime of one AccessToken in seconds. lifetime: Variable for the Lifetime of one AccessToken in seconds.
""" """
class __OnlyOne:
def __init__(self, arg):
self.val = arg
def __str__(self):
return repr(self) + self.val
instance = None instance = None
tokenList = None tokenList = None
lifetime = 60 lifetime = 60
@ -32,10 +27,6 @@ class AccesTokenController(Thread):
Initialize Thread and set tokenList empty. Initialize Thread and set tokenList empty.
""" """
LOGGER.info("Initialize AccessTokenController") LOGGER.info("Initialize AccessTokenController")
if not AccesTokenController.instance:
AccesTokenController.instance = AccesTokenController.__OnlyOne(arg)
else:
AccesTokenController.instance.val = arg
LOGGER.debug("Build Logger for VerificationThread") LOGGER.debug("Build Logger for VerificationThread")
@ -87,7 +78,7 @@ class AccesTokenController(Thread):
""" """
LOGGER.info("Create AccessToken") LOGGER.info("Create AccessToken")
now = datetime.ctime(datetime.now()) now = datetime.ctime(datetime.now())
token = hashlib.md5((now + user.password).encode('utf-8')).hexdigest() token = hashlib.md5((now + user.dn).encode('utf-8')).hexdigest()
accToken = AccessToken(user, token) accToken = AccessToken(user, token)
LOGGER.debug("Add AccessToken {} to current Tokens".format(accToken)) LOGGER.debug("Add AccessToken {} to current Tokens".format(accToken))
self.tokenList.append(accToken) self.tokenList.append(accToken)
@ -115,17 +106,20 @@ class AccesTokenController(Thread):
Verify that the AccesToken are not out of date. If one AccessToken out of date it will be deletet from tokenList. Verify that the AccesToken are not out of date. If one AccessToken out of date it will be deletet from tokenList.
""" """
valid_time=120
LOGGER.info("Start Thread for verification that the AccessToken are not out of date.") LOGGER.info("Start Thread for verification that the AccessToken are not out of date.")
while True: while True:
self.LOGGER.debug("Name: {}".format(self.getName()))
self.LOGGER.debug("Start to iterate through List of current Tokens") self.LOGGER.debug("Start to iterate through List of current Tokens")
for accToken in self.tokenList: for accToken in self.tokenList:
self.LOGGER.debug("Check if AccessToken {} is out of date".format(accToken)) self.LOGGER.debug("Check if AccessToken {} is out of date".format(accToken))
if (datetime.now() - accToken.timestamp).seconds > 7200: if (datetime.now() - accToken.timestamp).seconds > valid_time:
print("delete", accToken) print("delete", accToken)
self.LOGGER.info("Delete AccessToken {} from List of current Tokens".format(accToken)) self.LOGGER.info("Delete AccessToken {} from List of current Tokens".format(accToken))
self.tokenList.remove(accToken) self.tokenList.remove(accToken)
else: else:
self.LOGGER.debug("AccessToken {} is up to date. {} seconds left".format(accToken, 7200 - (datetime.now() - accToken.timestamp).seconds)) self.LOGGER.debug("AccessToken {} is up to date. {} seconds left".format(accToken, valid_time - (datetime.now() - accToken.timestamp).seconds))
self.LOGGER.debug("List of current Tokens: {}".format(self.tokenList)) self.LOGGER.debug("List of current Tokens: {}".format(self.tokenList))
self.LOGGER.info("Wait 10 Seconds") self.LOGGER.info("Wait 10 Seconds")
time.sleep(10) time.sleep(10)

View File

@ -0,0 +1,68 @@
import pymysql
from geruecht import Singleton
from geruecht.model.user import User
class DatabaseController(metaclass=Singleton):
'''
DatabaesController
Connect to the Database and execute sql-executions
'''
def __init__(self, url='192.168.5.108', user='wu5', password='E1n$tein', database='geruecht'):
self.url = url
self.user = user
self.password = password
self.database = database
self.connect()
def connect(self):
try:
self.db = pymysql.connect(self.url, self.user, self.password, self.database, cursorclass=pymysql.cursors.DictCursor)
except Exception as err:
raise err
def getAllUser(self):
cursor = self.db.cursor()
def getUser(self, username):
self.connect()
retVal = None
cursor = self.db.cursor()
cursor.execute("select * from user where cn='{}'".format(username))
data = cursor.fetchone()
if data:
retVal = User(data)
self.db.close()
return retVal
def insertUser(self, data):
self.connect()
cursor = self.db.cursor()
try:
cursor.execute("insert into user (cn, dn, firstname, lastname, `group`) VALUES ('{}','{}','{}','{}','{}')".format(
data['cn'], data['dn'], data['givenName'], data['sn'], data['group']))
self.db.commit()
except Exception as err:
self.db.rollback()
self.db.close()
raise err
self.db.close()
def updateUser(self, data):
self.connect()
cursor = self.db.cursor()
try:
cursor.execute("update user dn='{}', firstname='{}', lastname='{}', group='{}' where cn='{}'".format(
data['dn'], data['givenName'], data['sn'], data['group'], data['cn']))
self.db.commit()
except Exception as err:
self.db.rollback()
self.db.close()
raise err
self.db.close()
if __name__ == '__main__':
db = DatabaseController(user='tim')

View File

@ -0,0 +1,56 @@
import ldap
from geruecht import MONEY, USER, GASTRO, BAR, Singleton
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
self.dn = dn
self.connect()
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:
self.client.bind_s("cn={},ou=user,{}".format(username, self.dn), password)
self.client.unbind_s()
except:
self.client.unbind_s()
raise Exception("Invalid Password or Username")
def getUserData(self, username):
self.connect()
search_data = self.client.search_s('ou=user,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'cn={}'.format(username), ['cn', 'givenName', 'sn'])
retVal = search_data[0][1]
for k,v in retVal.items():
retVal[k] = v[0].decode('utf-8')
retVal['dn'] = self.dn
return retVal
def getGroup(self, username):
self.connect()
groups_data = self.client.search_s('ou=group,{}'.format(self.dn), ldap.SCOPE_SUBTREE, 'memberUID={}'.format(username), ['cn'])
if len(groups_data) == 0:
return USER
else:
data = groups_data[0][1]['cn'][0].decode('utf-8')
if data == 'finanzer':
return MONEY
elif data == 'gastro':
return GASTRO
elif data == 'bar':
return BAR
if __name__ == '__main__':
a = LDAPController()
a.getUserData('jhille')

View File

@ -1,10 +1,9 @@
from geruecht import db
from datetime import datetime from datetime import datetime
from geruecht import getLogger from geruecht import getLogger
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
class CreditList(db.Model): class CreditList():
""" DataBase Object Credit List: """ DataBase Object Credit List:
Attributes: Attributes:
@ -17,7 +16,7 @@ class CreditList(db.Model):
user_id: id from the User. user_id: id from the User.
""" """
LOGGER.debug("Initialize Geruecht") LOGGER.debug("Initialize Geruecht")
id = db.Column(db.Integer, primary_key=True) id = db.Colum(db.Integer, primary_key=True)
jan_guthaben = db.Column(db.Integer, nullable=False, default=0) jan_guthaben = db.Column(db.Integer, nullable=False, default=0)
jan_schulden = db.Column(db.Integer, nullable=False, default=0) jan_schulden = db.Column(db.Integer, nullable=False, default=0)

View File

@ -1,10 +1,11 @@
from geruecht import db, bcrypt, getLogger from geruecht import getLogger
from geruecht.model.creditList import CreditList from geruecht import db
#from geruecht.model.creditList import CreditList
from datetime import datetime from datetime import datetime
LOGGER = getLogger(__name__) LOGGER = getLogger(__name__)
class User(db.Model): class User():
""" Database Object for User """ Database Object for User
Table for all safed User Table for all safed User
@ -18,16 +19,16 @@ class User(db.Model):
group: Which group is the User? moneymaster, gastro, user or bar? group: Which group is the User? moneymaster, gastro, user or bar?
password: salted hashed password for the User. password: salted hashed password for the User.
""" """
id = db.Column(db.Integer, primary_key=True) def __init__(self, data):
userID = db.Column(db.String, nullable=False, unique=True) self.id = int(data['id'])
username = db.Column(db.String, nullable=False, unique=True) self.cn = data['cn']
firstname = db.Column(db.String, nullable=False) self.dn = data['dn']
lastname = db.Column(db.String, nullable=False) self.firstname = data['firstname']
group = db.Column(db.String, nullable=False) self.lastname = data['lastname']
password = db.Column(db.String, nullable=False) self.group = data['group']
geruechte = db.relationship('CreditList', backref='user', lazy=True)
#geruechte = db.relationship('CreditList', backref='user', lazy=True)
'''
def createGeruecht(self, amount=0, year=datetime.now().year): def createGeruecht(self, amount=0, year=datetime.now().year):
""" Create Geruecht """ Create Geruecht
@ -153,7 +154,7 @@ class User(db.Model):
int year of the geruecht int year of the geruecht
""" """
return geruecht.year return geruecht.year
'''
def toJSON(self): def toJSON(self):
""" Create Dic to dump in JSON """ Create Dic to dump in JSON
@ -161,14 +162,19 @@ class User(db.Model):
A Dic with static Attributes. A Dic with static Attributes.
""" """
dic = { dic = {
"userId": self.userID, "cn": self.cn,
"username": self.username, "dn": self.dn,
"firstname": self.firstname, "firstname": self.firstname,
"lastname": self.lastname, "lastname": self.lastname,
"group": self.group, "group": self.group,
} }
return dic return dic
def update(self):
data = ldap.getUserData(self.cn)
data['group'] = ldap.getGroup(self.cn)
db.updateUser(data)
def login(self, password): def login(self, password):
""" Login for the User """ Login for the User
@ -178,7 +184,14 @@ class User(db.Model):
A Bool. True if the password is correct and False if it isn't. A Bool. True if the password is correct and False if it isn't.
""" """
LOGGER.debug("Login User {}".format(self)) LOGGER.debug("Login User {}".format(self))
return True if bcrypt.check_password_hash(self.password, password) else False try:
from geruecht import ldapController as ldap
ldap.login(self.cn, password)
self.update()
return True
except:
return False
def __repr__(self): def __repr__(self):
return "User({}, {}, {})".format(self.userID, self.username, self.group) return "User({}, {}, {})".format(self.cn, self.dn, self.group)

View File

@ -1,7 +1,8 @@
from geruecht import app, db, accesTokenController, MONEY, BAR, USER, GASTRO, LOGGER from geruecht import app, db, accesTokenController, MONEY, BAR, USER, GASTRO, LOGGER
from geruecht import ldapController as ldap
from geruecht.model.user import User from geruecht.model.user import User
from geruecht.model.creditList import CreditList #from geruecht.model.creditList import CreditList
from geruecht.model.priceList import PriceList #from geruecht.model.priceList import PriceList
from datetime import datetime from datetime import datetime
from flask import request, jsonify from flask import request, jsonify
@ -61,8 +62,24 @@ def _login():
LOGGER.debug("JSON from request: {}".format(data)) LOGGER.debug("JSON from request: {}".format(data))
username = data['username'] username = data['username']
password = data['password'] password = data['password']
LOGGER.info("search {} in database".format(username))
user = db.getUser(username)
if user is None:
LOGGER.info("User {} not found. Authenticate over LDAP and create User.")
try:
ldap.login(username, password)
LOGGER.info("Authentification successfull. Search Group")
group = ldap.getGroup(username)
LOGGER.info("Get userdata from LDAP")
user_data = ldap.getUserData(username)
user_data['group'] = group
LOGGER.info('Insert user {} into database')
db.insertUser(user_data)
except Exception as err:
raise err
LOGGER.info("{} try to log in".format(username)) LOGGER.info("{} try to log in".format(username))
user = User.query.filter_by(username=username).first() user = db.getUser(username)
LOGGER.debug("User is {}".format(user)) LOGGER.debug("User is {}".format(user))
if user: if user:
LOGGER.debug("Check login for User {}".format(user)) LOGGER.debug("Check login for User {}".format(user))