diff --git a/flaschengeist/app.py b/flaschengeist/app.py index 266fa3d..d1cb5d7 100644 --- a/flaschengeist/app.py +++ b/flaschengeist/app.py @@ -7,6 +7,7 @@ from werkzeug.exceptions import HTTPException from . import logger from .system.config import config, configure_app +from .system.controller import roleController class CustomJSONEncoder(JSONEncoder): @@ -48,9 +49,11 @@ def __load_plugins(app): for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin'): logger.debug("Found plugin: >{}<".format(entry_point.name)) if config.get(entry_point.name, 'enabled', fallback=False): - logger.info("Loaded plugin >{}<".format(entry_point.name)) + blueprint, permissions = entry_point.load()() app.config["FG_PLUGINS"][entry_point.name] = True - app.register_blueprint(entry_point.load()()) + app.register_blueprint(blueprint) + roleController.create_permissions(permissions.values()) + logger.info("Loaded plugin >{}<".format(entry_point.name)) else: app.config["FG_PLUGINS"][entry_point.name] = False diff --git a/flaschengeist/modules/auth/__init__.py b/flaschengeist/modules/auth/__init__.py index 41fcf7f..3fb8447 100644 --- a/flaschengeist/modules/auth/__init__.py +++ b/flaschengeist/modules/auth/__init__.py @@ -18,7 +18,7 @@ auth_bp = Blueprint('auth', __name__) def register(): - return auth_bp + return auth_bp, {} ################################################# # Routes # diff --git a/flaschengeist/modules/schedule/__init__.py b/flaschengeist/modules/schedule/__init__.py index be354ac..4c8a72b 100644 --- a/flaschengeist/modules/schedule/__init__.py +++ b/flaschengeist/modules/schedule/__init__.py @@ -9,10 +9,11 @@ from flaschengeist.system.decorator import login_required from flaschengeist.system.models.event import EventKind schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule") +permissions = {} def register(): - return schedule_bp + return schedule_bp, permissions #################################################################################### @@ -70,7 +71,10 @@ def __get_events(year=datetime.now().year, month=datetime.now().month, day=None, begin += timedelta(days=day - 1) end = begin + timedelta(days=1) else: - end = datetime(year=year, month=month + 1, day=1) + if month == 12: + end = datetime(year=year + 1, month=1, day=1) + else: + end = datetime(year=year, month=month+1, day=1) events = eventController.get_events(begin, end) return jsonify(events) diff --git a/flaschengeist/modules/users/__init__.py b/flaschengeist/modules/users/__init__.py index 9cf2863..c1ac277 100644 --- a/flaschengeist/modules/users/__init__.py +++ b/flaschengeist/modules/users/__init__.py @@ -1,5 +1,5 @@ from flask import Blueprint, request, jsonify -from werkzeug.exceptions import NotFound, BadRequest +from werkzeug.exceptions import NotFound, BadRequest, Forbidden from flaschengeist import logger from flaschengeist.system.decorator import login_required @@ -7,9 +7,10 @@ from flaschengeist.system.controller import userController users_bp = Blueprint("users", __name__) +permissions = {'EDIT_USER': 'edit_user'} def register(): - return users_bp + return users_bp, permissions ################################################# # Routes # @@ -47,13 +48,16 @@ def __get_user(uid, **kwargs): @users_bp.route("/users/", methods=['PUT']) -@login_required()#roles=['edit_users']) +@login_required() def __edit_user(uid, **kwargs): logger.debug("Modify information of user {{ {} }}".format(uid)) user = userController.get_user(uid) if not user: raise NotFound + if uid != kwargs['access_token'].user.uid and user.has_permissions(permissions['EDIT_USER']): + return Forbidden + data = request.get_json() if 'password' not in data: raise BadRequest("Password is missing") diff --git a/flaschengeist/system/controller/accessTokenController.py b/flaschengeist/system/controller/accessTokenController.py index e3d375e..c4c2cfd 100644 --- a/flaschengeist/system/controller/accessTokenController.py +++ b/flaschengeist/system/controller/accessTokenController.py @@ -19,7 +19,7 @@ class AccessTokenController(metaclass=Singleton): def __init__(self, lifetime=1800): self.lifetime = lifetime - def validate_token(self, token, user_agent, roles): + def validate_token(self, token, user_agent, permissions): """ Verify access token Verify an AccessToken and Roles so if the User has permission or not. @@ -28,7 +28,7 @@ class AccessTokenController(metaclass=Singleton): Args: token: Token to verify. user_agent: User agent of browser to check - roles: Roles needed to access restricted routes + permissions: Permissions needed to access restricted routes Returns: An the AccessToken for this given Token or False. """ @@ -39,14 +39,14 @@ class AccessTokenController(metaclass=Singleton): if access_token.expires >= datetime.utcnow() and ( access_token.browser == user_agent.browser and access_token.platform == user_agent.platform): - if not roles or (roles and self.user_has_role(access_token.user, roles)): + if not permissions or access_token.user.has_permissions(permissions): access_token.refresh() db.session.commit() return access_token else: logger.debug("access token is out of date or invalid client used") self.delete_token(access_token) - logger.debug("no valid access token with token: {{ {} }} and roles: {{ {} }}".format(token, roles)) + logger.debug("no valid access token with token: {{ {} }} and permissions: {{ {} }}".format(token, permissions)) return False def create(self, user, user_agent=None) -> AccessToken: @@ -115,11 +115,3 @@ class AccessTokenController(metaclass=Singleton): deleted = AccessToken.query.filter(AccessToken.expires < datetime.utcnow()).delete() logger.debug("{} tokens have been removed".format(deleted)) db.session.commit() - - # TODO: is this needed? - def user_has_role(self, user, roles): - for group in user.groups: - for role in group.roles: - if role.name in roles: - return True - return False diff --git a/flaschengeist/system/decorator.py b/flaschengeist/system/decorator.py index de3b2df..cb71ce1 100644 --- a/flaschengeist/system/decorator.py +++ b/flaschengeist/system/decorator.py @@ -8,15 +8,15 @@ from flaschengeist import logger def login_required(**kwargs): from .controller.accessTokenController import AccessTokenController ac_controller = AccessTokenController() - roles = None - if "roles" in kwargs: - roles = kwargs["roles"] + permissions = None + if "permissions" in kwargs: + permissions = kwargs["roles"] def real_decorator(func): @wraps(func) def wrapper(*args, **kwargs): token = request.headers.get('Token') - access_token = ac_controller.validate_token(token, request.user_agent, roles) + access_token = ac_controller.validate_token(token, request.user_agent, permissions) if access_token: kwargs['access_token'] = access_token logger.debug("token {{ {} }} is valid".format(token)) diff --git a/flaschengeist/system/models/accessToken.py b/flaschengeist/system/models/accessToken.py index af80281..f19b2b0 100644 --- a/flaschengeist/system/models/accessToken.py +++ b/flaschengeist/system/models/accessToken.py @@ -18,7 +18,7 @@ class AccessToken(db.Model): user = db.relationship("User", back_populates="sessions") expires = db.Column(db.DateTime) - token = db.Column(db.String(30), unique=True) + token = db.Column(db.String(32), unique=True) lifetime = db.Column(db.Integer) browser = db.Column(db.String(30)) platform = db.Column(db.String(30))