From e8fc6c64b9fa774db70e69b9d77ad16f616745a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Gr=C3=B6ger?= Date: Thu, 19 Dec 2019 08:12:29 +0100 Subject: [PATCH] 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. --- geruecht/__init__.py | 34 ++++++++--- geruecht/controller/accesTokenController.py | 22 +++---- geruecht/controller/databaseController.py | 68 +++++++++++++++++++++ geruecht/controller/ldapController.py | 56 +++++++++++++++++ geruecht/model/creditList.py | 5 +- geruecht/model/user.py | 47 ++++++++------ geruecht/routes.py | 23 ++++++- 7 files changed, 208 insertions(+), 47 deletions(-) create mode 100644 geruecht/controller/databaseController.py create mode 100644 geruecht/controller/ldapController.py diff --git a/geruecht/__init__.py b/geruecht/__init__.py index 2e93a13..09d744b 100644 --- a/geruecht/__init__.py +++ b/geruecht/__init__.py @@ -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) diff --git a/geruecht/controller/accesTokenController.py b/geruecht/controller/accesTokenController.py index 93e7e32..c8594e1 100644 --- a/geruecht/controller/accesTokenController.py +++ b/geruecht/controller/accesTokenController.py @@ -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) diff --git a/geruecht/controller/databaseController.py b/geruecht/controller/databaseController.py new file mode 100644 index 0000000..c73ecb0 --- /dev/null +++ b/geruecht/controller/databaseController.py @@ -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') diff --git a/geruecht/controller/ldapController.py b/geruecht/controller/ldapController.py new file mode 100644 index 0000000..dbd5a40 --- /dev/null +++ b/geruecht/controller/ldapController.py @@ -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') diff --git a/geruecht/model/creditList.py b/geruecht/model/creditList.py index ddcc877..2370001 100644 --- a/geruecht/model/creditList.py +++ b/geruecht/model/creditList.py @@ -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) diff --git a/geruecht/model/user.py b/geruecht/model/user.py index 4ba9d7c..89d63f5 100644 --- a/geruecht/model/user.py +++ b/geruecht/model/user.py @@ -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) diff --git a/geruecht/routes.py b/geruecht/routes.py index cd192cb..2685794 100644 --- a/geruecht/routes.py +++ b/geruecht/routes.py @@ -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))