diff --git a/flaschengeist/modules/auth/__init__.py b/flaschengeist/modules/auth/__init__.py index 5e867ae..e17e143 100644 --- a/flaschengeist/modules/auth/__init__.py +++ b/flaschengeist/modules/auth/__init__.py @@ -1,7 +1,7 @@ ############################################# # Plugin: Auth # # Functionality: Allow management of # -# authentification, login, logout, etc # +# authentication, login, logout, etc # ############################################# from flask import Blueprint, current_app, request, jsonify @@ -24,7 +24,7 @@ def register(): return auth_bp ############################################ -## Routes ## +# Routes # ############################################ @@ -68,10 +68,10 @@ def _login(): def _logout(**kwargs): try: logger.debug("logout user") - accToken = kwargs['accToken'] - logger.debug("accesstoken is {{ {} }}".format(accToken)) - logger.debug("delete accesstoken") - access_controller.deleteAccessToken(accToken) + token = kwargs['accToken'] + logger.debug("access token is {{ {} }}".format(token)) + logger.debug("delete access token") + access_controller.deleteAccessToken(token) access_controller.clearExpired() logger.info("return ok logout user") return jsonify({"ok": "ok"}) @@ -81,7 +81,7 @@ def _logout(**kwargs): @auth_bp.route("/user/getAccessTokens", methods=['GET', 'POST']) -#@auth_bp.route("/accessTokens", methods=['GET', 'POST']) +# @auth_bp.route("/accessTokens", methods=['GET', 'POST']) @login_required() def _getAccessTokens(**kwargs): try: @@ -102,12 +102,12 @@ def _getAccessTokens(**kwargs): @login_required() def _getLifeTime(**kwargs): try: - logger.debug("get lifetime of accesstoken") - accToken = kwargs['accToken'] - logger.debug("accessToken is {{ {} }}".format(accToken)) - return jsonify({"value": accToken.lifetime}) + logger.debug("get lifetime of access token") + token = kwargs['accToken'] + logger.debug("accessToken is {{ {} }}".format(token)) + return jsonify({"value": token.lifetime}) except Exception as err: - logger.warning("exception in get lifetime of accesstoken.", exc_info=True) + logger.warning("exception in get lifetime of access token.", exc_info=True) return jsonify({"error": str(err)}), 500 @@ -125,7 +125,7 @@ def _saveLifeTime(**kwargs): token.lifetime = lifetime logger.info("update access token timestamp") token = access_controller.update(token) - return jsonify({"value": token.lifetime }) + return jsonify({"value": token.lifetime}) except Exception as err: logger.warning( "exception in save lifetime for access token.", exc_info=True) diff --git a/flaschengeist/system/controller/accessTokenController.py b/flaschengeist/system/controller/accessTokenController.py index 033d383..3b0ed76 100644 --- a/flaschengeist/system/controller/accessTokenController.py +++ b/flaschengeist/system/controller/accessTokenController.py @@ -10,9 +10,9 @@ logger = logging.getLogger("flaschenpost") class AccessTokenController(metaclass=Singleton): - """ Control all createt AccesToken + """ Control all created AccessToken - This Class create, delete, find and manage AccesToken. + This Class create, delete, find and manage AccessToken. Attributes: lifetime: Variable for the Lifetime of one AccessToken in seconds. @@ -25,10 +25,10 @@ class AccessTokenController(metaclass=Singleton): Initialize Thread and set tokenList empty. """ - logger.debug("init accesstoken controller") + logger.debug("init access token controller") self.lifetime = lifetime - def validate(self, token, roles): + def validate_token(self, token, roles): """ Verify access token Verify an AccessToken and Group so if the User has permission or not. @@ -41,19 +41,19 @@ class AccessTokenController(metaclass=Singleton): An the AccessToken for this given Token or False. """ logger.debug("check token {{ {} }} is valid".format(token)) - for accToken in AccessToken.query.filter_by(token=token): - time_end = accToken.timestamp + timedelta(seconds=accToken.lifetime) + for access_token in AccessToken.query.filter_by(token=token): + time_end = access_token.timestamp + timedelta(seconds=access_token.lifetime) now = datetime.utcnow() logger.debug("now is {{ {} }}, endtime is {{ {} }}".format(now, time_end)) if now <= time_end: - logger.debug("check if token {{ {} }} is same as {{ {} }}".format(token, accToken)) - if not roles or (roles and self.userHasRole(accToken.user, roles)): - accToken.updateTimestamp() + logger.debug("check if token {{ {} }} is same as {{ {} }}".format(token, access_token)) + if not roles or (roles and self.userHasRole(access_token.user, roles)): + access_token.updateTimestamp() db.session.commit() - return accToken + return access_token else: - logger.debug("access token is {{ {} }} out of date".format(accToken)) - db.session.delete(accToken) + logger.debug("access token is {{ {} }} out of date".format(access_token)) + db.session.delete(access_token) db.session.commit() logger.debug("no valid access token with token: {{ {} }} and group: {{ {} }}".format(token, roles)) return False @@ -79,7 +79,8 @@ class AccessTokenController(metaclass=Singleton): """ logger.debug("create access token") token_str = secrets.token_hex(16) - token = AccessToken(token=token_str, user=user, lifetime=self.lifetime, browser=user_agent.browser, platform=user_agent.platform) + token = AccessToken(token=token_str, user=user, lifetime=self.lifetime, + browser=user_agent.browser, platform=user_agent.platform) db.session.add(token) db.session.commit() @@ -89,22 +90,23 @@ class AccessTokenController(metaclass=Singleton): def getAccessTokensFromUser(self, user): return AccessToken.query.filter(AccessToken.user == user) - def deleteAccessToken(self, accessToken): - if accessToken is isinstance(accessToken, AccessToken): - db.session.delete(accessToken) + @staticmethod + def delete_token(token): + if token is isinstance(token, AccessToken): + db.session.delete(token) else: - AccessToken.query.filter_by(token=accessToken).delete() + AccessToken.query.filter_by(token=token).delete() db.session.commit() @staticmethod - def update_token(self, token): - token.updateTimestamp() + def update_token(token): + token.update_timestamp() db.session.commit() def clear_expired(self): logger.debug("Clear expired AccessToken") - mightExpired = datetime.utcnow() - timedelta(seconds=self.lifetime) - tokens = AccessToken.query.filter(AccessToken.timestamp < mightExpired) + might_expired = datetime.utcnow() - timedelta(seconds=self.lifetime) + tokens = AccessToken.query.filter(AccessToken.timestamp < might_expired) logger.debug(tokens) for token in tokens: if token.timestamp < datetime.utcnow() - timedelta(seconds=token.lifetime): diff --git a/flaschengeist/system/decorator.py b/flaschengeist/system/decorator.py index a428e10..3942cd8 100644 --- a/flaschengeist/system/decorator.py +++ b/flaschengeist/system/decorator.py @@ -15,7 +15,7 @@ def login_required(**kwargs): def wrapper(*args, **kwargs): token = request.headers.get('Token') logger.debug("token is {{ {} }}".format(token)) - access_token = ac_controller.validate(token, roles) + access_token = ac_controller.validate_token(token, roles) logger.debug("accToken is {{ {} }}".format(access_token)) kwargs['accToken'] = access_token if access_token: diff --git a/flaschengeist/system/models/accessToken.py b/flaschengeist/system/models/accessToken.py index 3d9fac8..6003568 100644 --- a/flaschengeist/system/models/accessToken.py +++ b/flaschengeist/system/models/accessToken.py @@ -25,12 +25,12 @@ class AccessToken(db.Model): browser = db.Column(db.String(30)) platform = db.Column(db.String(30)) - def updateTimestamp(self): + def update_timestamp(self): """ Update the Timestamp Update the Timestamp to the current Time. """ - logger.debug("update timestamp from accesstoken {{ {} }}".format(self)) + logger.debug("update timestamp from access token {{ {} }}".format(self)) self.timestamp = datetime.utcnow() def toJSON(self): @@ -61,7 +61,9 @@ class AccessToken(db.Model): return other - self.timestamp def __str__(self): - return "AccessToken(user={}, token={}, timestamp={}, lifetime={}".format(self.user, self.token, self.timestamp, self.lifetime) + return "AccessToken(user={}, token={}, timestamp={}, lifetime={}".format( + self.user, self.token, self.timestamp, self.lifetime) def __repr__(self): - return "AccessToken(user={}, token={}, timestamp={}, lifetime={}".format(self.user, self.token, self.timestamp, self.lifetime) + return "AccessToken(user={}, token={}, timestamp={}, lifetime={}".format( + self.user, self.token, self.timestamp, self.lifetime) diff --git a/flaschengeist/system/models/user.py b/flaschengeist/system/models/user.py index 4844c70..0dd0321 100644 --- a/flaschengeist/system/models/user.py +++ b/flaschengeist/system/models/user.py @@ -2,51 +2,53 @@ from ..database import db from sqlalchemy.orm.collections import attribute_mapped_collection from flask import current_app from werkzeug.local import LocalProxy + logger = LocalProxy(lambda: current_app.logger) association_table = db.Table('user_group', - db.Column('user_id', db.Integer, db.ForeignKey('user.id')), - db.Column('group_id', db.Integer, db.ForeignKey('group.id')) -) + db.Column('user_id', db.Integer, db.ForeignKey('user.id')), + db.Column('group_id', db.Integer, db.ForeignKey('group.id')) + ) class User(db.Model): """ Database Object for User - Table for all safed User + Table for all saved User Attributes: id: Id in Database as Primary Key. uid: User ID used by authentication provider - displayname: Name to show + display_name: Name to show firstname: Firstname of the User lastname: Lastname of the User mail: mail address of the User """ __tablename__ = 'user' - id = db.Column(db.Integer, primary_key=True) - uid = db.Column(db.String(30)) - displayname = db.Column(db.String(30)) - firstname = db.Column(db.String(30)) - lastname = db.Column(db.String(30)) - mail = db.Column(db.String(30)) - groups = db.relationship("Group", secondary=association_table) - sessions = db.relationship("AccessToken", back_populates="user") - attributes = db.relationship("UserAttribute", collection_class=attribute_mapped_collection('name'), cascade="all, delete") + id = db.Column(db.Integer, primary_key=True) + uid = db.Column(db.String(30)) + display_name = db.Column(db.String(30)) + firstname = db.Column(db.String(30)) + lastname = db.Column(db.String(30)) + mail = db.Column(db.String(30)) + groups = db.relationship("Group", secondary=association_table) + sessions = db.relationship("AccessToken", back_populates="user") + attributes = db.relationship("UserAttribute", collection_class=attribute_mapped_collection('name'), + cascade="all, delete") - def setAttribute(self, name, value): + def set_attribute(self, name, value): if name in self.attributes: self.attributes[name].value = value else: self.attributes[name] = UserAttribute(name=name, value=value) - def addGroup(self, name): + def add_group(self, name): r = Group.query.filter_by(name=name).first() if not r: r = Group(name=name) self.groups.append(r) - - def updateData(self, data): + + def update_data(self, data): logger.debug("update data of user") if 'uid' in data: self.uid = data['uid'] @@ -56,14 +58,14 @@ class User(db.Model): self.lastname = data['lastname'] if 'mail' in data: self.mail = data['mail'] - if 'displayname' in data: - self.displayname = data['displayname'] + if 'display_name' in data: + self.display_name = data['display_name'] def toJSON(self): return { # TODO: username should be UID? "username": self.uid, - "displayname": self.displayname, + "display_name": self.display_name, "firstname": self.firstname, "lastname": self.lastname, "mail": self.mail, @@ -73,20 +75,21 @@ class User(db.Model): class UserAttribute(db.Model): __tablename__ = 'userAttribute' - id = db.Column(db.Integer, primary_key=True) - user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) - name = db.Column(db.String(30)) + id = db.Column(db.Integer, primary_key=True) + user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) + name = db.Column(db.String(30)) value = db.Column(db.String(192)) + group_permission_association_table = db.Table('group_permission', - db.Column('group_id', db.Integer, db.ForeignKey('group.id')), - db.Column('permission_id', db.Integer, db.ForeignKey('permission.id')) -) + db.Column('group_id', db.Integer, db.ForeignKey('group.id')), + db.Column('permission_id', db.Integer, db.ForeignKey('permission.id')) + ) class Group(db.Model): __tablename__ = 'group' - id = db.Column(db.Integer, primary_key=True) + id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(30)) permissions = db.relationship("Permission", secondary=group_permission_association_table) diff --git a/setup.py b/setup.py index e2fd23a..4720a1c 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,8 @@ setup( packages=find_packages(), package_data={'': ['*.yml']}, scripts=['run_flaschengeist'], - install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", "flask_cors"], + install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", + "flask_cors", "werkzeug"], extras_require={ 'ldap': [ 'flask_ldapconn',