Add permissions when plugins are loaded

This commit is contained in:
Ferdinand Thiessen 2020-10-04 01:27:05 +02:00
parent 4cd68d7e81
commit f495829fc7
7 changed files with 28 additions and 25 deletions

View File

@ -7,6 +7,7 @@ from werkzeug.exceptions import HTTPException
from . import logger from . import logger
from .system.config import config, configure_app from .system.config import config, configure_app
from .system.controller import roleController
class CustomJSONEncoder(JSONEncoder): class CustomJSONEncoder(JSONEncoder):
@ -48,9 +49,11 @@ def __load_plugins(app):
for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin'): for entry_point in pkg_resources.iter_entry_points('flaschengeist.plugin'):
logger.debug("Found plugin: >{}<".format(entry_point.name)) logger.debug("Found plugin: >{}<".format(entry_point.name))
if config.get(entry_point.name, 'enabled', fallback=False): 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.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: else:
app.config["FG_PLUGINS"][entry_point.name] = False app.config["FG_PLUGINS"][entry_point.name] = False

View File

@ -18,7 +18,7 @@ auth_bp = Blueprint('auth', __name__)
def register(): def register():
return auth_bp return auth_bp, {}
################################################# #################################################
# Routes # # Routes #

View File

@ -9,10 +9,11 @@ from flaschengeist.system.decorator import login_required
from flaschengeist.system.models.event import EventKind from flaschengeist.system.models.event import EventKind
schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule") schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule")
permissions = {}
def register(): 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) begin += timedelta(days=day - 1)
end = begin + timedelta(days=1) end = begin + timedelta(days=1)
else: 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) events = eventController.get_events(begin, end)
return jsonify(events) return jsonify(events)

View File

@ -1,5 +1,5 @@
from flask import Blueprint, request, jsonify 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 import logger
from flaschengeist.system.decorator import login_required from flaschengeist.system.decorator import login_required
@ -7,9 +7,10 @@ from flaschengeist.system.controller import userController
users_bp = Blueprint("users", __name__) users_bp = Blueprint("users", __name__)
permissions = {'EDIT_USER': 'edit_user'}
def register(): def register():
return users_bp return users_bp, permissions
################################################# #################################################
# Routes # # Routes #
@ -47,13 +48,16 @@ def __get_user(uid, **kwargs):
@users_bp.route("/users/<uid>", methods=['PUT']) @users_bp.route("/users/<uid>", methods=['PUT'])
@login_required()#roles=['edit_users']) @login_required()
def __edit_user(uid, **kwargs): def __edit_user(uid, **kwargs):
logger.debug("Modify information of user {{ {} }}".format(uid)) logger.debug("Modify information of user {{ {} }}".format(uid))
user = userController.get_user(uid) user = userController.get_user(uid)
if not user: if not user:
raise NotFound raise NotFound
if uid != kwargs['access_token'].user.uid and user.has_permissions(permissions['EDIT_USER']):
return Forbidden
data = request.get_json() data = request.get_json()
if 'password' not in data: if 'password' not in data:
raise BadRequest("Password is missing") raise BadRequest("Password is missing")

View File

@ -19,7 +19,7 @@ class AccessTokenController(metaclass=Singleton):
def __init__(self, lifetime=1800): def __init__(self, lifetime=1800):
self.lifetime = lifetime self.lifetime = lifetime
def validate_token(self, token, user_agent, roles): def validate_token(self, token, user_agent, permissions):
""" Verify access token """ Verify access token
Verify an AccessToken and Roles so if the User has permission or not. Verify an AccessToken and Roles so if the User has permission or not.
@ -28,7 +28,7 @@ class AccessTokenController(metaclass=Singleton):
Args: Args:
token: Token to verify. token: Token to verify.
user_agent: User agent of browser to check user_agent: User agent of browser to check
roles: Roles needed to access restricted routes permissions: Permissions needed to access restricted routes
Returns: Returns:
An the AccessToken for this given Token or False. An the AccessToken for this given Token or False.
""" """
@ -39,14 +39,14 @@ class AccessTokenController(metaclass=Singleton):
if access_token.expires >= datetime.utcnow() and ( if access_token.expires >= datetime.utcnow() and (
access_token.browser == user_agent.browser and access_token.browser == user_agent.browser and
access_token.platform == user_agent.platform): 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() access_token.refresh()
db.session.commit() db.session.commit()
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_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 return False
def create(self, user, user_agent=None) -> AccessToken: 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() deleted = AccessToken.query.filter(AccessToken.expires < datetime.utcnow()).delete()
logger.debug("{} tokens have been removed".format(deleted)) logger.debug("{} tokens have been removed".format(deleted))
db.session.commit() 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

View File

@ -8,15 +8,15 @@ from flaschengeist import logger
def login_required(**kwargs): def login_required(**kwargs):
from .controller.accessTokenController import AccessTokenController from .controller.accessTokenController import AccessTokenController
ac_controller = AccessTokenController() ac_controller = AccessTokenController()
roles = None permissions = None
if "roles" in kwargs: if "permissions" in kwargs:
roles = kwargs["roles"] permissions = kwargs["roles"]
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('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: if access_token:
kwargs['access_token'] = access_token kwargs['access_token'] = access_token
logger.debug("token {{ {} }} is valid".format(token)) logger.debug("token {{ {} }} is valid".format(token))

View File

@ -18,7 +18,7 @@ class AccessToken(db.Model):
user = db.relationship("User", back_populates="sessions") user = db.relationship("User", back_populates="sessions")
expires = db.Column(db.DateTime) 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) lifetime = db.Column(db.Integer)
browser = db.Column(db.String(30)) browser = db.Column(db.String(30))
platform = db.Column(db.String(30)) platform = db.Column(db.String(30))