Rename AccessToken model to Session, same with controller.
This commit is contained in:
parent
ec05cde746
commit
c629f5abf3
|
@ -1,7 +1,6 @@
|
||||||
""" Server-package
|
""" Server-package
|
||||||
|
|
||||||
Initialize app, CORS, database and add it to the application.
|
Initialize app, CORS, database and add it to the application.
|
||||||
Initialize also a singleton for the AccessTokenController and start the Thread.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import yaml
|
import yaml
|
||||||
|
|
|
@ -56,11 +56,14 @@ def __load_plugins(app):
|
||||||
|
|
||||||
def install_all():
|
def install_all():
|
||||||
from flaschengeist.system.database import db
|
from flaschengeist.system.database import db
|
||||||
from flaschengeist.system.models import user, event, accessToken
|
from flaschengeist.system.models import user, event, session
|
||||||
|
|
||||||
db.create_all()
|
db.create_all()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
for name, plugin in current_app.config["FG_PLUGINS"].items():
|
for name, plugin in current_app.config["FG_PLUGINS"].items():
|
||||||
|
if not plugin:
|
||||||
|
logger.debug("Skip disabled plugin {}".format(name))
|
||||||
|
continue
|
||||||
logger.info("Install plugin {}".format(name))
|
logger.info("Install plugin {}".format(name))
|
||||||
plugin.install()
|
plugin.install()
|
||||||
if plugin.permissions:
|
if plugin.permissions:
|
||||||
|
|
|
@ -7,6 +7,7 @@ class Plugin:
|
||||||
def __init__(self, config=None, blueprint=None, permissions={}):
|
def __init__(self, config=None, blueprint=None, permissions={}):
|
||||||
self.blueprint = blueprint
|
self.blueprint = blueprint
|
||||||
self.permissions = permissions
|
self.permissions = permissions
|
||||||
|
self.version = "dummy"
|
||||||
|
|
||||||
def install(self):
|
def install(self):
|
||||||
"""Installation routine
|
"""Installation routine
|
||||||
|
@ -14,6 +15,11 @@ class Plugin:
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def serialize(self):
|
||||||
|
return {
|
||||||
|
"version": self.version,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class AuthPlugin(Plugin):
|
class AuthPlugin(Plugin):
|
||||||
def login(self, user, pw):
|
def login(self, user, pw):
|
||||||
|
|
|
@ -11,9 +11,9 @@ from werkzeug.local import LocalProxy
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
from flaschengeist.modules import Plugin
|
from flaschengeist.modules import Plugin
|
||||||
from flaschengeist.system.decorator import login_required
|
from flaschengeist.system.decorator import login_required
|
||||||
from flaschengeist.system.controller import accessTokenController, userController, messageController
|
from flaschengeist.system.controller import sessionController, userController, messageController
|
||||||
|
|
||||||
access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController())
|
session_controller = LocalProxy(lambda: sessionController.SessionController())
|
||||||
auth_bp = Blueprint("auth", __name__)
|
auth_bp = Blueprint("auth", __name__)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,10 +33,10 @@ class AuthRoutePlugin(Plugin):
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth", methods=["POST"])
|
@auth_bp.route("/auth", methods=["POST"])
|
||||||
def _create_token():
|
def _login():
|
||||||
"""Login User
|
"""Login User
|
||||||
|
|
||||||
Login in User and create an AccessToken for the User.
|
Login in User and create a Session for the User.
|
||||||
Requires POST data {'userid': string, 'password': string}
|
Requires POST data {'userid': string, 'password': string}
|
||||||
Returns:
|
Returns:
|
||||||
A JSON-File with user information and created token or errors
|
A JSON-File with user information and created token or errors
|
||||||
|
@ -54,55 +54,55 @@ def _create_token():
|
||||||
if not user:
|
if not user:
|
||||||
raise Unauthorized
|
raise Unauthorized
|
||||||
logger.debug("user is {{ {} }}".format(user))
|
logger.debug("user is {{ {} }}".format(user))
|
||||||
token = access_controller.create(user, user_agent=request.user_agent)
|
session = session_controller.create(user, user_agent=request.user_agent)
|
||||||
logger.debug("access token is {{ {} }}".format(token))
|
logger.debug("token is {{ {} }}".format(session.token))
|
||||||
logger.info("User {{ {} }} success login.".format(userid))
|
logger.info("User {{ {} }} success login.".format(userid))
|
||||||
|
|
||||||
# Lets cleanup the DB
|
# Lets cleanup the DB
|
||||||
access_controller.clear_expired()
|
session_controller.clear_expired()
|
||||||
return jsonify({"user": user, "token": token, "permissions": user.get_permissions()})
|
return jsonify({"session": session, "permissions": user.get_permissions()})
|
||||||
|
|
||||||
|
|
||||||
@auth_bp.route("/auth", methods=["GET"])
|
@auth_bp.route("/auth", methods=["GET"])
|
||||||
@login_required()
|
@login_required()
|
||||||
def _get_tokens(access_token, **kwargs):
|
def _get_tokens(access_token, **kwargs):
|
||||||
tokens = access_controller.get_users_tokens(access_token.user)
|
tokens = session_controller.get_users_sessions(access_token.user)
|
||||||
a = messageController.Message(access_token.user, "Go", "Bar")
|
a = messageController.Message(access_token.user, "Go", "Bar")
|
||||||
messageController.send_message(a)
|
messageController.send_message(a)
|
||||||
return jsonify(tokens)
|
return jsonify(tokens)
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
|
||||||
@auth_bp.route("/auth/<token>", methods=["DELETE"])
|
@auth_bp.route("/auth/<token>", methods=["DELETE"])
|
||||||
def _delete_token(token, access_token, **kwargs):
|
@login_required()
|
||||||
|
def _delete_token(access_token, token, **kwargs):
|
||||||
logger.debug("Try to delete access token {{ {} }}".format(token))
|
logger.debug("Try to delete access token {{ {} }}".format(token))
|
||||||
token = access_controller.get_token(token, access_token.user)
|
token = session_controller.get_session(token, access_token.user)
|
||||||
if not token:
|
if not token:
|
||||||
logger.debug("Token not found in database!")
|
logger.debug("Token not found in database!")
|
||||||
# Return 403 error, so that users can not bruteforce tokens
|
# Return 403 error, so that users can not bruteforce tokens
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
access_controller.delete_token(token)
|
session_controller.delete_session(token)
|
||||||
access_controller.clear_expired()
|
session_controller.clear_expired()
|
||||||
return jsonify({"ok": "ok"})
|
return jsonify({"ok": "ok"})
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
|
||||||
@auth_bp.route("/auth/<token>", methods=["GET"])
|
@auth_bp.route("/auth/<token>", methods=["GET"])
|
||||||
|
@login_required()
|
||||||
def _get_token(token, access_token, **kwargs):
|
def _get_token(token, access_token, **kwargs):
|
||||||
logger.debug("get token {{ {} }}".format(token))
|
logger.debug("get token {{ {} }}".format(token))
|
||||||
token = access_controller.get_token(token, access_token.user)
|
session = session_controller.get_session(token, access_token.user)
|
||||||
if not token:
|
if not token:
|
||||||
# Return 403 error, so that users can not bruteforce tokens
|
# Return 403 error, so that users can not bruteforce tokens
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
return jsonify(token)
|
return jsonify({"session": session, "permissions": session.user.get_permissions()})
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
|
||||||
@auth_bp.route("/auth/<token>", methods=["PUT"])
|
@auth_bp.route("/auth/<token>", methods=["PUT"])
|
||||||
|
@login_required()
|
||||||
def _set_lifetime(token, access_token, **kwargs):
|
def _set_lifetime(token, access_token, **kwargs):
|
||||||
token = access_controller.get_token(token, access_token.user)
|
token = session_controller.get_token(token, access_token.user)
|
||||||
if not token:
|
if not token:
|
||||||
# Return 403 error, so that users can not bruteforce tokens
|
# Return 403 error, so that users can not bruteforce tokens
|
||||||
# Valid tokens from other users and invalid tokens now are looking the same
|
# Valid tokens from other users and invalid tokens now are looking the same
|
||||||
|
@ -110,7 +110,7 @@ def _set_lifetime(token, access_token, **kwargs):
|
||||||
try:
|
try:
|
||||||
lifetime = request.get_json()["value"]
|
lifetime = request.get_json()["value"]
|
||||||
logger.debug("set lifetime {{ {} }} to access token {{ {} }}".format(lifetime, token))
|
logger.debug("set lifetime {{ {} }} to access token {{ {} }}".format(lifetime, token))
|
||||||
access_controller.set_lifetime(token, lifetime)
|
session_controller.set_lifetime(token, lifetime)
|
||||||
return jsonify({"ok": "ok"})
|
return jsonify({"ok": "ok"})
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
raise BadRequest
|
raise BadRequest
|
||||||
|
|
|
@ -37,17 +37,17 @@ class AuthLDAP(AuthPlugin):
|
||||||
def login(self, user, password):
|
def login(self, user, password):
|
||||||
if not user:
|
if not user:
|
||||||
return False
|
return False
|
||||||
return self.ldap.authenticate(user.uid, password, "uid", self.dn)
|
return self.ldap.authenticate(user.userid, password, "uid", self.dn)
|
||||||
|
|
||||||
def update_user(self, user):
|
def update_user(self, user):
|
||||||
self.ldap.connection.search(
|
self.ldap.connection.search(
|
||||||
"ou=user,{}".format(self.dn),
|
"ou=user,{}".format(self.dn),
|
||||||
"(uid={})".format(user.uid),
|
"(uid={})".format(user.userid),
|
||||||
SUBTREE,
|
SUBTREE,
|
||||||
attributes=["uid", "givenName", "sn", "mail"],
|
attributes=["uid", "givenName", "sn", "mail"],
|
||||||
)
|
)
|
||||||
r = self.ldap.connection.response[0]["attributes"]
|
r = self.ldap.connection.response[0]["attributes"]
|
||||||
if r["uid"][0] == user.uid:
|
if r["uid"][0] == user.userid:
|
||||||
user.set_attribute("DN", self.ldap.connection.response[0]["dn"])
|
user.set_attribute("DN", self.ldap.connection.response[0]["dn"])
|
||||||
user.firstname = r["givenName"][0]
|
user.firstname = r["givenName"][0]
|
||||||
user.lastname = r["sn"][0]
|
user.lastname = r["sn"][0]
|
||||||
|
@ -55,7 +55,7 @@ class AuthLDAP(AuthPlugin):
|
||||||
user.mail = r["mail"][0]
|
user.mail = r["mail"][0]
|
||||||
if "displayName" in r:
|
if "displayName" in r:
|
||||||
user.display_name = r["displayName"][0]
|
user.display_name = r["displayName"][0]
|
||||||
for group in self._get_groups(user.uid):
|
for group in self._get_groups(user.userid):
|
||||||
user.add_role(group)
|
user.add_role(group)
|
||||||
|
|
||||||
def _get_groups(self, uid):
|
def _get_groups(self, uid):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import binascii
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import flaschengeist.modules as modules
|
from flaschengeist.modules import AuthPlugin
|
||||||
from flaschengeist.system.models.user import User
|
from flaschengeist.system.models.user import User
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ def _verify_password(stored_password, provided_password):
|
||||||
return pass_hash == stored_password
|
return pass_hash == stored_password
|
||||||
|
|
||||||
|
|
||||||
class AuthPlain(modules.Auth):
|
class AuthPlain(AuthPlugin):
|
||||||
def login(self, user: User, password: str):
|
def login(self, user: User, password: str):
|
||||||
if user and "password" in user.attributes:
|
if user and "password" in user.attributes:
|
||||||
return _verify_password(user.attributes["password"].value, password)
|
return _verify_password(user.attributes["password"].value, password)
|
||||||
|
|
|
@ -42,7 +42,7 @@ def _bar(**kwargs):
|
||||||
type = 'credit'
|
type = 'credit'
|
||||||
else:
|
else:
|
||||||
type = 'amount'
|
type = 'amount'
|
||||||
dic[user.uid] = {"username": user.uid,
|
dic[user.userid] = {"username": user.userid,
|
||||||
"firstname": user.firstname,
|
"firstname": user.firstname,
|
||||||
"lastname": user.lastname,
|
"lastname": user.lastname,
|
||||||
"amount": all,
|
"amount": all,
|
||||||
|
@ -50,8 +50,8 @@ def _bar(**kwargs):
|
||||||
"type": type,
|
"type": type,
|
||||||
"limit": user.limit,
|
"limit": user.limit,
|
||||||
"autoLock": user.autoLock
|
"autoLock": user.autoLock
|
||||||
}
|
}
|
||||||
dic[user.uid]['last_seen'] = {"year": user.last_seen.year, "month": user.last_seen.month, "day": user.last_seen.day, "hour": user.last_seen.hour, "minute": user.last_seen.minute, "second": user.last_seen.second} if user.last_seen else None
|
dic[user.userid]['last_seen'] = {"year": user.last_seen.year, "month": user.last_seen.month, "day": user.last_seen.day, "hour": user.last_seen.hour, "minute": user.last_seen.minute, "second": user.last_seen.second} if user.last_seen else None
|
||||||
debug.debug("return {{ {} }}".format(dic))
|
debug.debug("return {{ {} }}".format(dic))
|
||||||
return jsonify(dic)
|
return jsonify(dic)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Base:
|
||||||
def getCreditListFromUser(self, user, **kwargs):
|
def getCreditListFromUser(self, user, **kwargs):
|
||||||
try:
|
try:
|
||||||
if type(user) is User:
|
if type(user) is User:
|
||||||
if user.uid == 'extern':
|
if user.userid == 'extern':
|
||||||
return []
|
return []
|
||||||
cursor = self.db.connection.cursor()
|
cursor = self.db.connection.cursor()
|
||||||
if 'year' in kwargs:
|
if 'year' in kwargs:
|
||||||
|
|
|
@ -83,7 +83,7 @@ class Base:
|
||||||
cursor = self.db.connection.cursor()
|
cursor = self.db.connection.cursor()
|
||||||
groups = self._convertGroupToString(user.group)
|
groups = self._convertGroupToString(user.group)
|
||||||
cursor.execute("insert into user (uid, dn, firstname, lastname, gruppe, lockLimit, locked, autoLock, mail) VALUES ('{}','{}','{}','{}','{}',{},{},{},'{}')".format(
|
cursor.execute("insert into user (uid, dn, firstname, lastname, gruppe, lockLimit, locked, autoLock, mail) VALUES ('{}','{}','{}','{}','{}',{},{},{},'{}')".format(
|
||||||
user.uid, user.dn, user.firstname, user.lastname, groups, user.limit, user.locked, user.autoLock, user.mail))
|
user.userid, user.dn, user.firstname, user.lastname, groups, user.limit, user.locked, user.autoLock, user.mail))
|
||||||
self.db.connection.commit()
|
self.db.connection.commit()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
@ -96,7 +96,7 @@ class Base:
|
||||||
cursor = self.db.connection.cursor()
|
cursor = self.db.connection.cursor()
|
||||||
groups = self._convertGroupToString(user.group)
|
groups = self._convertGroupToString(user.group)
|
||||||
sql = "update user set dn='{}', firstname='{}', lastname='{}', gruppe='{}', lockLimit={}, locked={}, autoLock={}, mail='{}' where uid='{}'".format(
|
sql = "update user set dn='{}', firstname='{}', lastname='{}', gruppe='{}', lockLimit={}, locked={}, autoLock={}, mail='{}' where uid='{}'".format(
|
||||||
user.dn, user.firstname, user.lastname, groups, user.limit, user.locked, user.autoLock, user.mail, user.uid)
|
user.dn, user.firstname, user.lastname, groups, user.limit, user.locked, user.autoLock, user.mail, user.userid)
|
||||||
print(sql)
|
print(sql)
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
self.db.connection.commit()
|
self.db.connection.commit()
|
||||||
|
@ -109,7 +109,7 @@ class Base:
|
||||||
try:
|
try:
|
||||||
cursor = self.db.connection.cursor()
|
cursor = self.db.connection.cursor()
|
||||||
sql = "update user set last_seen='{}' where uid='{}'".format(
|
sql = "update user set last_seen='{}' where uid='{}'".format(
|
||||||
time, user.uid)
|
time, user.userid)
|
||||||
print(sql)
|
print(sql)
|
||||||
cursor.execute(sql)
|
cursor.execute(sql)
|
||||||
self.db.connection.commit()
|
self.db.connection.commit()
|
||||||
|
|
|
@ -29,8 +29,8 @@ def _getFinanzer(**kwargs):
|
||||||
users = mainController.getAllUsersfromDB()
|
users = mainController.getAllUsersfromDB()
|
||||||
dic = {}
|
dic = {}
|
||||||
for user in users:
|
for user in users:
|
||||||
dic[user.uid] = user.toJSON()
|
dic[user.userid] = user.toJSON()
|
||||||
dic[user.uid]['creditList'] = {
|
dic[user.userid]['creditList'] = {
|
||||||
credit.year: credit.toJSON() for credit in user.geruechte}
|
credit.year: credit.toJSON() for credit in user.geruechte}
|
||||||
debug.debug("return {{ {} }}".format(dic))
|
debug.debug("return {{ {} }}".format(dic))
|
||||||
return jsonify(dic)
|
return jsonify(dic)
|
||||||
|
@ -168,8 +168,8 @@ def _finanzerAddUser(**kwargs):
|
||||||
users = mainController.getAllUsersfromDB()
|
users = mainController.getAllUsersfromDB()
|
||||||
dic = {}
|
dic = {}
|
||||||
for user in users:
|
for user in users:
|
||||||
dic[user.uid] = user.toJSON()
|
dic[user.userid] = user.toJSON()
|
||||||
dic[user.uid]['creditList'] = {
|
dic[user.userid]['creditList'] = {
|
||||||
credit.year: credit.toJSON() for credit in user.geruechte}
|
credit.year: credit.toJSON() for credit in user.geruechte}
|
||||||
debug.debug("return {{ {} }}".format(dic))
|
debug.debug("return {{ {} }}".format(dic))
|
||||||
return jsonify(dic), 200
|
return jsonify(dic), 200
|
||||||
|
|
|
@ -94,9 +94,9 @@ class MainController(#mainJobKindController.Base,
|
||||||
|
|
||||||
def __updateDataFromLDAP(self, user):
|
def __updateDataFromLDAP(self, user):
|
||||||
logger.info("update data from ldap for user {{ {} }}".format(user))
|
logger.info("update data from ldap for user {{ {} }}".format(user))
|
||||||
groups = ldap.getGroup(user.uid)
|
groups = ldap.getGroup(user.userid)
|
||||||
logger.debug("ldap gorups are {{ {} }}".format(groups))
|
logger.debug("ldap gorups are {{ {} }}".format(groups))
|
||||||
user_data = ldap.getUserData(user.uid)
|
user_data = ldap.getUserData(user.userid)
|
||||||
logger.debug("ldap data is {{ {} }}".format(user_data))
|
logger.debug("ldap data is {{ {} }}".format(user_data))
|
||||||
user_data['gruppe'] = groups
|
user_data['gruppe'] = groups
|
||||||
user_data['group'] = groups
|
user_data['group'] = groups
|
||||||
|
|
|
@ -34,7 +34,7 @@ class Base:
|
||||||
amount, username, month, year))
|
amount, username, month, year))
|
||||||
user = self.getUser(username)
|
user = self.getUser(username)
|
||||||
debug.debug("user is {{ {} }}".format(user))
|
debug.debug("user is {{ {} }}".format(user))
|
||||||
if user.uid == 'extern':
|
if user.userid == 'extern':
|
||||||
debug.debug("user is extern user, so exit add amount")
|
debug.debug("user is extern user, so exit add amount")
|
||||||
return
|
return
|
||||||
if not user.locked or finanzer:
|
if not user.locked or finanzer:
|
||||||
|
@ -60,7 +60,7 @@ class Base:
|
||||||
credit, username, month, year))
|
credit, username, month, year))
|
||||||
user = self.getUser(username)
|
user = self.getUser(username)
|
||||||
debug.debug("user is {{ {} }}".format(user))
|
debug.debug("user is {{ {} }}".format(user))
|
||||||
if user.uid == 'extern':
|
if user.userid == 'extern':
|
||||||
debug.debug("user is extern user, so exit add credit")
|
debug.debug("user is extern user, so exit add credit")
|
||||||
return
|
return
|
||||||
user.addCredit(credit, year=year, month=month)
|
user.addCredit(credit, year=year, month=month)
|
||||||
|
|
|
@ -57,7 +57,7 @@ def __edit_user(uid, **kwargs):
|
||||||
if not user:
|
if not user:
|
||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
if uid != kwargs["access_token"].user.uid and user.has_permissions(permissions["EDIT_USER"]):
|
if uid != kwargs["access_token"].user.userid and user.has_permissions(permissions["EDIT_USER"]):
|
||||||
return Forbidden
|
return Forbidden
|
||||||
|
|
||||||
data = request.get_json()
|
data = request.get_json()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import secrets
|
import secrets
|
||||||
from ..models.accessToken import AccessToken
|
from ..models.session import Session
|
||||||
from flaschengeist.system.database import db
|
from flaschengeist.system.database import db
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
from werkzeug.exceptions import Forbidden
|
from werkzeug.exceptions import Forbidden
|
||||||
|
@ -7,22 +7,22 @@ from datetime import datetime, timezone
|
||||||
from . import Singleton
|
from . import Singleton
|
||||||
|
|
||||||
|
|
||||||
class AccessTokenController(metaclass=Singleton):
|
class SessionController(metaclass=Singleton):
|
||||||
"""Control all created AccessToken
|
"""Control all created Sessions
|
||||||
|
|
||||||
This Class create, delete, find and manage AccessToken.
|
This Class create, delete, find and manage Sessions.
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
lifetime: Variable for the Lifetime of one AccessToken in seconds.
|
lifetime: Variable for the Lifetime of a Session in seconds.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, lifetime=1800):
|
def __init__(self, lifetime=1800):
|
||||||
self.lifetime = lifetime
|
self.lifetime = lifetime
|
||||||
|
|
||||||
def validate_token(self, token, user_agent, permissions):
|
def validate_token(self, token, user_agent, permissions):
|
||||||
"""Verify access token
|
"""Verify session
|
||||||
|
|
||||||
Verify an AccessToken and Roles so if the User has permission or not.
|
Verify a Session and Roles so if the User has permission or not.
|
||||||
Retrieves the access token if valid else retrieves False
|
Retrieves the access token if valid else retrieves False
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -30,10 +30,10 @@ class AccessTokenController(metaclass=Singleton):
|
||||||
user_agent: User agent of browser to check
|
user_agent: User agent of browser to check
|
||||||
permissions: Permissions needed to access restricted routes
|
permissions: Permissions needed to access restricted routes
|
||||||
Returns:
|
Returns:
|
||||||
An the AccessToken for this given Token or False.
|
A Session for this given Token or False.
|
||||||
"""
|
"""
|
||||||
logger.debug("check token {{ {} }} is valid".format(token))
|
logger.debug("check token {{ {} }} is valid".format(token))
|
||||||
access_token = AccessToken.query.filter_by(token=token).one_or_none()
|
access_token = Session.query.filter_by(token=token).one_or_none()
|
||||||
if access_token:
|
if access_token:
|
||||||
logger.debug("token found, check if expired or invalid user agent differs")
|
logger.debug("token found, check if expired or invalid user agent differs")
|
||||||
if access_token.expires >= datetime.utcnow() and (
|
if access_token.expires >= datetime.utcnow() and (
|
||||||
|
@ -45,34 +45,34 @@ class AccessTokenController(metaclass=Singleton):
|
||||||
return access_token
|
return access_token
|
||||||
else:
|
else:
|
||||||
logger.debug("access token is out of date or invalid client used")
|
logger.debug("access token is out of date or invalid client used")
|
||||||
self.delete_token(access_token)
|
self.delete_session(access_token)
|
||||||
logger.debug("no valid access token with token: {{ {} }} and permissions: {{ {} }}".format(token, permissions))
|
logger.debug("no valid access token with token: {{ {} }} and permissions: {{ {} }}".format(token, permissions))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def create(self, user, user_agent=None) -> AccessToken:
|
def create(self, user, user_agent=None) -> Session:
|
||||||
"""Create an AccessToken
|
"""Create a Session
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user: For which User is to create an AccessToken
|
user: For which User is to create a Session
|
||||||
user_agent: User agent to identify session
|
user_agent: User agent to identify session
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
AccessToken: A created Token for User
|
Session: A created Token for User
|
||||||
"""
|
"""
|
||||||
logger.debug("create access token")
|
logger.debug("create access token")
|
||||||
token_str = secrets.token_hex(16)
|
token_str = secrets.token_hex(16)
|
||||||
token = AccessToken(
|
session = Session(
|
||||||
token=token_str, user=user, lifetime=self.lifetime, browser=user_agent.browser, platform=user_agent.platform
|
token=token_str, user=user, lifetime=self.lifetime, browser=user_agent.browser, platform=user_agent.platform
|
||||||
)
|
)
|
||||||
token.refresh()
|
session.refresh()
|
||||||
db.session.add(token)
|
db.session.add(session)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
logger.debug("access token is {{ {} }}".format(token))
|
logger.debug("access token is {{ {} }}".format(session.token))
|
||||||
return token
|
return session
|
||||||
|
|
||||||
def get_token(self, token, owner=None):
|
def get_session(self, token, owner=None):
|
||||||
"""Retrieves AccessToken from token string
|
"""Retrieves Session from token string
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
token (str): Token string
|
token (str): Token string
|
||||||
|
@ -81,38 +81,38 @@ class AccessTokenController(metaclass=Singleton):
|
||||||
Raises:
|
Raises:
|
||||||
Forbidden: Raised if owner is set but does not match
|
Forbidden: Raised if owner is set but does not match
|
||||||
Returns:
|
Returns:
|
||||||
AccessToken: Token object identified by given token string
|
Session: Token object identified by given token string
|
||||||
"""
|
"""
|
||||||
access_token = AccessToken.query.filter(AccessToken.token == token).one_or_none()
|
session = Session.query.filter(Session.token == token).one_or_none()
|
||||||
if access_token and (owner and owner != access_token.user):
|
if session and (owner and owner != session.user):
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
return access_token
|
return session
|
||||||
|
|
||||||
def get_users_tokens(self, user):
|
def get_users_sessions(self, user):
|
||||||
return AccessToken.query.filter(AccessToken.user == user)
|
return Session.query.filter(Session.user == user)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def delete_token(token: AccessToken):
|
def delete_session(token: Session):
|
||||||
"""Deletes given AccessToken
|
"""Deletes given Session
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
token (AccessToken): Token to delete
|
token (Session): Token to delete
|
||||||
"""
|
"""
|
||||||
db.session.delete(token)
|
db.session.delete(token)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_token(token):
|
def update_session(session):
|
||||||
token.refresh()
|
session.refresh()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
def set_lifetime(self, token, lifetime):
|
def set_lifetime(self, session, lifetime):
|
||||||
token.lifetime = lifetime
|
session.lifetime = lifetime
|
||||||
self.update_token(token)
|
self.update_session(session)
|
||||||
|
|
||||||
def clear_expired(self):
|
def clear_expired(self):
|
||||||
"""Remove expired tokens from database"""
|
"""Remove expired tokens from database"""
|
||||||
logger.debug("Clear expired AccessToken")
|
logger.debug("Clear expired Sessions")
|
||||||
deleted = AccessToken.query.filter(AccessToken.expires < datetime.utcnow()).delete()
|
deleted = Session.query.filter(Session.expires < datetime.utcnow()).delete()
|
||||||
logger.debug("{} tokens have been removed".format(deleted))
|
logger.debug("{} sessions have been removed".format(deleted))
|
||||||
db.session.commit()
|
db.session.commit()
|
|
@ -7,9 +7,9 @@ from flaschengeist import logger
|
||||||
|
|
||||||
def login_user(username, password):
|
def login_user(username, password):
|
||||||
logger.info("login user {{ {} }}".format(username))
|
logger.info("login user {{ {} }}".format(username))
|
||||||
user = User.query.filter_by(uid=username).one_or_none()
|
user = User.query.filter(User.userid == username).one_or_none()
|
||||||
if user is None:
|
if user is None:
|
||||||
user = User(uid=username)
|
user = User(userid=username)
|
||||||
db.session.add(user)
|
db.session.add(user)
|
||||||
if current_app.config["FG_AUTH_BACKEND"].login(user, password):
|
if current_app.config["FG_AUTH_BACKEND"].login(user, password):
|
||||||
update_user(user)
|
update_user(user)
|
||||||
|
@ -49,4 +49,4 @@ def get_user_by_role(role: Role):
|
||||||
|
|
||||||
|
|
||||||
def get_user(uid):
|
def get_user(uid):
|
||||||
return User.query.filter(User.uid == uid).one_or_none()
|
return User.query.filter(User.userid == uid).one_or_none()
|
||||||
|
|
|
@ -6,9 +6,9 @@ from flaschengeist import logger
|
||||||
|
|
||||||
|
|
||||||
def login_required(**kwargs):
|
def login_required(**kwargs):
|
||||||
from .controller.accessTokenController import AccessTokenController
|
from .controller.sessionController import SessionController
|
||||||
|
|
||||||
ac_controller = AccessTokenController()
|
ac_controller = SessionController()
|
||||||
permissions = None
|
permissions = None
|
||||||
if "permissions" in kwargs:
|
if "permissions" in kwargs:
|
||||||
permissions = kwargs["roles"]
|
permissions = kwargs["roles"]
|
||||||
|
@ -16,7 +16,7 @@ def login_required(**kwargs):
|
||||||
def real_decorator(func):
|
def real_decorator(func):
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
token = request.headers.get("Token")
|
token = request.headers.get("Authorization").split(" ")[-1]
|
||||||
access_token = ac_controller.validate_token(token, request.user_agent, permissions)
|
access_token = ac_controller.validate_token(token, request.user_agent, permissions)
|
||||||
if access_token:
|
if access_token:
|
||||||
kwargs["access_token"] = access_token
|
kwargs["access_token"] = access_token
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
|
from .user import User
|
||||||
from ..database import db
|
from ..database import db
|
||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
from flaschengeist import logger
|
from flaschengeist import logger
|
||||||
|
|
||||||
|
|
||||||
class AccessToken(db.Model):
|
class Session(db.Model):
|
||||||
"""Model for an AccessToken
|
"""Model for a Session
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
expires: Is a Datetime from current Time.
|
expires: Is a Datetime from current Time.
|
||||||
|
@ -16,20 +18,20 @@ class AccessToken(db.Model):
|
||||||
__tablename__ = "session"
|
__tablename__ = "session"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
|
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
|
||||||
user = db.relationship("User", back_populates="sessions")
|
user: User = db.relationship("User", back_populates="sessions")
|
||||||
|
|
||||||
expires = db.Column(db.DateTime)
|
expires: datetime = db.Column(db.DateTime)
|
||||||
token = db.Column(db.String(32), unique=True)
|
token: str = db.Column(db.String(32), unique=True)
|
||||||
lifetime = db.Column(db.Integer)
|
lifetime: int = db.Column(db.Integer)
|
||||||
browser = db.Column(db.String(30))
|
browser: str = db.Column(db.String(30))
|
||||||
platform = db.Column(db.String(30))
|
platform: str = db.Column(db.String(30))
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
"""Update the Timestamp
|
"""Update the Timestamp
|
||||||
|
|
||||||
Update the Timestamp to the current Time.
|
Update the Timestamp to the current Time.
|
||||||
"""
|
"""
|
||||||
logger.debug("update timestamp from access token {{ {} }}".format(self))
|
logger.debug("update timestamp from session with token {{ {} }}".format(self))
|
||||||
self.expires = datetime.utcnow() + timedelta(seconds=self.lifetime)
|
self.expires = datetime.utcnow() + timedelta(seconds=self.lifetime)
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
|
@ -42,14 +44,10 @@ class AccessToken(db.Model):
|
||||||
"token": self.token,
|
"token": self.token,
|
||||||
"expires": self.expires.replace(tzinfo=timezone.utc),
|
"expires": self.expires.replace(tzinfo=timezone.utc),
|
||||||
"lifetime": self.lifetime,
|
"lifetime": self.lifetime,
|
||||||
|
"user": self.user,
|
||||||
"browser": self.browser,
|
"browser": self.browser,
|
||||||
"platform": self.platform,
|
"platform": self.platform,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __eq__(self, token):
|
def __eq__(self, token):
|
||||||
return compare_digest(self.token, token)
|
return compare_digest(self.token, token)
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "AccessToken(user={}, token={}, expires={}, lifetime={})".format(
|
|
||||||
self.user, self.token, self.expires, self.lifetime
|
|
||||||
)
|
|
|
@ -28,13 +28,13 @@ class User(db.Model):
|
||||||
|
|
||||||
__tablename__ = "user"
|
__tablename__ = "user"
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
uid = db.Column(db.String(30))
|
userid = db.Column(db.String(30))
|
||||||
display_name = db.Column(db.String(30))
|
display_name = db.Column(db.String(30))
|
||||||
firstname = db.Column(db.String(30))
|
firstname = db.Column(db.String(30))
|
||||||
lastname = db.Column(db.String(30))
|
lastname = db.Column(db.String(30))
|
||||||
mail = db.Column(db.String(30))
|
mail = db.Column(db.String(30))
|
||||||
roles = db.relationship("Role", secondary=association_table)
|
roles = db.relationship("Role", secondary=association_table)
|
||||||
sessions = db.relationship("AccessToken", back_populates="user")
|
sessions = db.relationship("Session", back_populates="user")
|
||||||
attributes = db.relationship(
|
attributes = db.relationship(
|
||||||
"UserAttribute", collection_class=attribute_mapped_collection("name"), cascade="all, delete"
|
"UserAttribute", collection_class=attribute_mapped_collection("name"), cascade="all, delete"
|
||||||
)
|
)
|
||||||
|
@ -53,8 +53,8 @@ class User(db.Model):
|
||||||
|
|
||||||
def update_data(self, data):
|
def update_data(self, data):
|
||||||
logger.debug("update data of user")
|
logger.debug("update data of user")
|
||||||
if "uid" in data:
|
if "userid" in data:
|
||||||
self.uid = data["uid"]
|
self.userid = data["userid"]
|
||||||
if "firstname" in data:
|
if "firstname" in data:
|
||||||
self.firstname = data["firstname"]
|
self.firstname = data["firstname"]
|
||||||
if "lastname" in data:
|
if "lastname" in data:
|
||||||
|
@ -76,7 +76,7 @@ class User(db.Model):
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
return {
|
return {
|
||||||
"userid": self.uid,
|
"userid": self.userid,
|
||||||
"display_name": self.display_name,
|
"display_name": self.display_name,
|
||||||
"firstname": self.firstname,
|
"firstname": self.firstname,
|
||||||
"lastname": self.lastname,
|
"lastname": self.lastname,
|
||||||
|
|
Loading…
Reference in New Issue