Added Role controller

This commit is contained in:
Ferdinand Thiessen 2020-10-04 01:25:50 +02:00
parent bf33529bf1
commit 4cd68d7e81
13 changed files with 177 additions and 17 deletions

View File

@ -58,7 +58,7 @@ class AuthLDAP(modules.Auth):
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.uid):
user.add_group(group) user.add_role(group)
def _get_groups(self, uid): def _get_groups(self, uid):
groups = [] groups = []

View File

@ -0,0 +1,87 @@
from flask import Blueprint, request, jsonify
from werkzeug.exceptions import NotFound, BadRequest, Forbidden
from flaschengeist.system.decorator import login_required
from flaschengeist.system.controller import roleController
roles_bp = Blueprint("roles", __name__)
permissions = {}
def register():
return roles_bp, permissions
######################################################
# Routes #
# #
# /roles POST: register new #
# GET: get all roles #
# /roles/permissions GET: get all permissions #
# /roles/<rid> GET: get role with rid #
# PUT: modify role / permission #
# DELETE: remove role #
######################################################
@roles_bp.route("/roles", methods=['POST'])
@login_required()
def __add_role():
data = request.get_json()
if not data or "name" not in data:
raise BadRequest
if "permissions" in data:
permissions = data["permissions"]
role = roleController.create_role(data["name"], permissions)
return jsonify({"ok": "ok", "id": role.id})
@roles_bp.route("/roles", methods=['GET'])
@login_required()
def __list_roles(**kwargs):
roles = roleController.get_roles()
return jsonify(roles)
@roles_bp.route("/roles/permissions", methods=['GET'])
@login_required()
def __list_permissions(**kwargs):
permissions = roleController.get_permissions()
return jsonify(permissions)
@roles_bp.route("/roles/<rid>", methods=['GET'])
@login_required()
def __get_role(rid, **kwargs):
role = roleController.get_role(rid)
if role:
return jsonify({
"id": role.id,
"name": role,
"permissions": role.permissions
})
raise NotFound
@roles_bp.route("/roles/<rid>", methods=['PUT'])
@login_required()
def __edit_role(rid, **kwargs):
role = roleController.get_role(rid)
if not role:
raise NotFound
data = request.get_json()
if 'name' in data:
role.name = data["name"]
if "permissions" in data:
roleController.set_permissions(role, data["permissions"])
roleController.update_role(role)
return jsonify({"ok": "ok"})
@roles_bp.route("/roles/<rid>", methods=['DELETE'])
@login_required()
def __delete_role(rid, **kwargs):
if not roleController.delete_role(rid):
raise NotFound
return jsonify({"ok": "ok"})

View File

@ -28,6 +28,9 @@ config.read_dict({
'auth': { 'auth': {
'enabled': True 'enabled': True
}, },
'roles': {
'enabled': True
},
'users': { 'users': {
'enabled': True 'enabled': True
} }

View File

@ -0,0 +1,58 @@
from flask import current_app
from sqlalchemy.exc import IntegrityError
from werkzeug.exceptions import BadRequest
from flaschengeist.system.models.user import Role, Permission
from flaschengeist.system.database import db
from flaschengeist import logger
def get_roles():
return Role.query.all()
def get_role(rid):
return Role.query.get(rid)
def get_permissions():
return Permission.query.all()
def update_role(role):
db.session.commit()
def set_permissions(role, permissions):
for name in permissions:
p = Permission.query.filter(Permission.name == name).one_or_none()
if not p:
raise BadRequest("Invalid permission name >{}<".format(name))
role.permissions.append(p)
db.session.commit()
def create_permissions(permissions):
for permission in permissions:
if Permission.query.filter(Permission.name == permission).count() > 0:
continue
p = Permission(name=permission)
db.session.add(p)
db.session.commit()
def create_role(name, permissions=[]):
role = Role(name=name)
db.session.add(role)
set_permissions(role, permissions)
return role.id
def delete_role(id):
try:
num = Role.query.filter(Role.id == id).delete()
except IntegrityError:
logger.debug("IntegrityError: Role might still be in use", exc_info=True)
raise BadRequest("Role still in use")
db.session.commit()
return num == 1

View File

@ -5,9 +5,9 @@ from werkzeug.local import LocalProxy
logger = LocalProxy(lambda: current_app.logger) logger = LocalProxy(lambda: current_app.logger)
association_table = db.Table('user_group', association_table = db.Table('user_x_role',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')), db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('group_id', db.Integer, db.ForeignKey('group.id')) db.Column('role_id', db.Integer, db.ForeignKey('role.id'))
) )
@ -31,7 +31,7 @@ class User(db.Model):
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))
groups = db.relationship("Group", secondary=association_table) roles = db.relationship("Role", secondary=association_table)
sessions = db.relationship("AccessToken", back_populates="user") sessions = db.relationship("AccessToken", back_populates="user")
attributes = db.relationship("UserAttribute", collection_class=attribute_mapped_collection('name'), attributes = db.relationship("UserAttribute", collection_class=attribute_mapped_collection('name'),
cascade="all, delete") cascade="all, delete")
@ -42,11 +42,11 @@ class User(db.Model):
else: else:
self.attributes[name] = UserAttribute(name=name, value=value) self.attributes[name] = UserAttribute(name=name, value=value)
def add_group(self, name): def add_role(self, name):
r = Group.query.filter_by(name=name).first() r = Role.query.filter_by(name=name).first()
if not r: if not r:
r = Group(name=name) r = Role(name=name)
self.groups.append(r) self.roles.append(r)
def update_data(self, data): def update_data(self, data):
logger.debug("update data of user") logger.debug("update data of user")
@ -61,6 +61,13 @@ class User(db.Model):
if 'display_name' in data: if 'display_name' in data:
self.display_name = data['display_name'] self.display_name = data['display_name']
def has_permissions(self, permissions):
for role in self.roles:
for permission in role.permissions:
if permission.name in permissions:
return True
return False
def serialize(self): def serialize(self):
return { return {
# TODO: username should be UID? # TODO: username should be UID?
@ -69,29 +76,29 @@ class User(db.Model):
"firstname": self.firstname, "firstname": self.firstname,
"lastname": self.lastname, "lastname": self.lastname,
"mail": self.mail, "mail": self.mail,
"groups": ["user"] + [g.name for g in self.groups] "roles": ["user"] + [r.name for r in self.roles]
} }
class UserAttribute(db.Model): class UserAttribute(db.Model):
__tablename__ = 'userAttribute' __tablename__ = 'user_attribute'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) user = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
name = db.Column(db.String(30)) name = db.Column(db.String(30))
value = db.Column(db.String(192)) value = db.Column(db.String(192))
group_permission_association_table = db.Table('group_permission', role_permission_association_table = db.Table('role_x_permission',
db.Column('group_id', db.Integer, db.ForeignKey('group.id')), db.Column('role_id', db.Integer, db.ForeignKey('role.id')),
db.Column('permission_id', db.Integer, db.ForeignKey('permission.id')) db.Column('permission_id', db.Integer, db.ForeignKey('permission.id'))
) )
class Group(db.Model): class Role(db.Model):
__tablename__ = 'group' __tablename__ = 'role'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30)) name = db.Column(db.String(30), unique=True)
permissions = db.relationship("Permission", secondary=group_permission_association_table) permissions = db.relationship("Permission", secondary=role_permission_association_table, cascade="all, delete")
def serialize(self): def serialize(self):
return self.name return self.name
@ -100,4 +107,7 @@ class Group(db.Model):
class Permission(db.Model): class Permission(db.Model):
__tablename__ = 'permission' __tablename__ = 'permission'
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30)) name = db.Column(db.String(30), unique=True)
def serialize(self):
return self.name

View File

@ -18,12 +18,14 @@ setup(
"flask_cors", "flask_cors",
"werkzeug", "werkzeug",
"bjoern", "bjoern",
"python-dateutil"
], ],
extras_require={"ldap": ["flask_ldapconn", "ldap3"]}, extras_require={"ldap": ["flask_ldapconn", "ldap3"]},
entry_points={ entry_points={
"flaschengeist.plugin": [ "flaschengeist.plugin": [
"auth = flaschengeist.modules.auth:register", "auth = flaschengeist.modules.auth:register",
"users = flaschengeist.modules.users:register", "users = flaschengeist.modules.users:register",
"roles = flaschengeist.modules.roles:register",
"schedule = flaschengeist.modules.schedule:register", "schedule = flaschengeist.modules.schedule:register",
], ],
"flaschengeist.auth": [ "flaschengeist.auth": [