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
import sys
MONEY = "moneymaster"
GASTRO = "gastro"
USER = "user"
BAR = "bar"
FORMATTER = logging.Formatter("%(asctime)s%(name)s%(levelname)s%(message)s")
logFileHandler = WatchedFileHandler("testlog.log")
@ -29,6 +34,18 @@ def getLogger(logger_name):
LOGGER = getLogger(__name__)
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_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
@ -41,7 +58,7 @@ app = Flask(__name__)
CORS(app)
# app.config['SECRET_KEY'] = '0a657b97ef546da90b2db91862ad4e29'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
#db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
accesTokenController = AccesTokenController("GERUECHT")
accesTokenController.start()
@ -49,16 +66,13 @@ accesTokenController.start()
# login_manager.login_view = 'login'
# login_manager.login_message_category = 'info'
MONEY = "moneymaster"
GASTRO = "gastro"
USER = "user"
BAR = "bar"
from geruecht import routes
from geruecht.baruser.routes import baruser
from geruecht.finanzer.routes import finanzer
#from geruecht.baruser.routes import baruser
#from geruecht.finanzer.routes import finanzer
LOGGER.info("Registrate bluebrints")
app.register_blueprint(baruser)
app.register_blueprint(finanzer)
#LOGGER.info("Registrate bluebrints")
#app.register_blueprint(baruser)
#app.register_blueprint(finanzer)

View File

@ -6,8 +6,9 @@ from threading import Thread
import hashlib
import logging
from logging.handlers import WatchedFileHandler
from geruecht import Singleton
class AccesTokenController(Thread):
class AccesTokenController(Thread, metaclass=Singleton):
""" Control all createt AccesToken
This Class create, delete, find and manage AccesToken.
@ -16,12 +17,6 @@ class AccesTokenController(Thread):
tokenList: List of currents AccessToken
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
tokenList = None
lifetime = 60
@ -32,10 +27,6 @@ class AccesTokenController(Thread):
Initialize Thread and set tokenList empty.
"""
LOGGER.info("Initialize AccessTokenController")
if not AccesTokenController.instance:
AccesTokenController.instance = AccesTokenController.__OnlyOne(arg)
else:
AccesTokenController.instance.val = arg
LOGGER.debug("Build Logger for VerificationThread")
@ -87,7 +78,7 @@ class AccesTokenController(Thread):
"""
LOGGER.info("Create AccessToken")
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)
LOGGER.debug("Add AccessToken {} to current Tokens".format(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.
"""
valid_time=120
LOGGER.info("Start Thread for verification that the AccessToken are not out of date.")
while True:
self.LOGGER.debug("Name: {}".format(self.getName()))
self.LOGGER.debug("Start to iterate through List of current Tokens")
for accToken in self.tokenList:
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)
self.LOGGER.info("Delete AccessToken {} from List of current Tokens".format(accToken))
self.tokenList.remove(accToken)
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.info("Wait 10 Seconds")
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 geruecht import getLogger
LOGGER = getLogger(__name__)
class CreditList(db.Model):
class CreditList():
""" DataBase Object Credit List:
Attributes:
@ -17,7 +16,7 @@ class CreditList(db.Model):
user_id: id from the User.
"""
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_schulden = db.Column(db.Integer, nullable=False, default=0)

View File

@ -1,10 +1,11 @@
from geruecht import db, bcrypt, getLogger
from geruecht.model.creditList import CreditList
from geruecht import getLogger
from geruecht import db
#from geruecht.model.creditList import CreditList
from datetime import datetime
LOGGER = getLogger(__name__)
class User(db.Model):
class User():
""" Database Object for 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?
password: salted hashed password for the User.
"""
id = db.Column(db.Integer, primary_key=True)
userID = db.Column(db.String, nullable=False, unique=True)
username = db.Column(db.String, nullable=False, unique=True)
firstname = db.Column(db.String, nullable=False)
lastname = db.Column(db.String, nullable=False)
group = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
geruechte = db.relationship('CreditList', backref='user', lazy=True)
def __init__(self, data):
self.id = int(data['id'])
self.cn = data['cn']
self.dn = data['dn']
self.firstname = data['firstname']
self.lastname = data['lastname']
self.group = data['group']
#geruechte = db.relationship('CreditList', backref='user', lazy=True)
'''
def createGeruecht(self, amount=0, year=datetime.now().year):
""" Create Geruecht
@ -153,7 +154,7 @@ class User(db.Model):
int year of the geruecht
"""
return geruecht.year
'''
def toJSON(self):
""" Create Dic to dump in JSON
@ -161,14 +162,19 @@ class User(db.Model):
A Dic with static Attributes.
"""
dic = {
"userId": self.userID,
"username": self.username,
"cn": self.cn,
"dn": self.dn,
"firstname": self.firstname,
"lastname": self.lastname,
"group": self.group,
}
return dic
def update(self):
data = ldap.getUserData(self.cn)
data['group'] = ldap.getGroup(self.cn)
db.updateUser(data)
def login(self, password):
""" 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.
"""
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):
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 ldapController as ldap
from geruecht.model.user import User
from geruecht.model.creditList import CreditList
from geruecht.model.priceList import PriceList
#from geruecht.model.creditList import CreditList
#from geruecht.model.priceList import PriceList
from datetime import datetime
from flask import request, jsonify
@ -61,8 +62,24 @@ def _login():
LOGGER.debug("JSON from request: {}".format(data))
username = data['username']
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))
user = User.query.filter_by(username=username).first()
user = db.getUser(username)
LOGGER.debug("User is {}".format(user))
if user:
LOGGER.debug("Check login for User {}".format(user))