added access control model and more stuff around access mgmt
This commit is contained in:
@@ -33,7 +33,6 @@ def main():
|
|||||||
pre_fill_table()
|
pre_fill_table()
|
||||||
update_recorder_models_database()
|
update_recorder_models_database()
|
||||||
|
|
||||||
|
|
||||||
app.run(debug=True, host="0.0.0.0")
|
app.run(debug=True, host="0.0.0.0")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,13 +22,17 @@ user_model = api_user.model('User', {
|
|||||||
'last_name': fields.String(required=True, description='The user\'s last name'),
|
'last_name': fields.String(required=True, description='The user\'s last name'),
|
||||||
'email': fields.String(required=True, description='The user\'s email address'),
|
'email': fields.String(required=True, description='The user\'s email address'),
|
||||||
'nickname': fields.String(required=False, description='The user\'s nick name'),
|
'nickname': fields.String(required=False, description='The user\'s nick name'),
|
||||||
|
'role': fields.String(required=False, description='Role a user might have (in addition to group memberships)'),
|
||||||
|
'effective_permissions': fields.List(
|
||||||
|
fields.String(required=True), required=False, description="List of permissions (groups + (optional) role)."
|
||||||
|
),
|
||||||
'groups': fields.List(
|
'groups': fields.List(
|
||||||
fields.Nested(api_user.model('user_group', {'id': fields.Integer(), 'name': fields.String()})),
|
fields.Nested(api_user.model('user_group', {'id': fields.Integer(), 'name': fields.String()})),
|
||||||
required=False, description='Group memberships.'),
|
required=False, description='Group memberships.'),
|
||||||
})
|
})
|
||||||
|
|
||||||
user_update_parser = api_user.parser()
|
user_update_parser = api_user.parser()
|
||||||
user_update_parser.add_argument('email', type=inputs.email, required=False, nullable=False, store_missing=False)
|
user_update_parser.add_argument('email', type=inputs.email(), required=False, nullable=False, store_missing=False)
|
||||||
user_update_parser.add_argument('nickname', type=str, required=False, store_missing=False)
|
user_update_parser.add_argument('nickname', type=str, required=False, store_missing=False)
|
||||||
user_update_parser.add_argument('first_name', type=str, required=False, store_missing=False)
|
user_update_parser.add_argument('first_name', type=str, required=False, store_missing=False)
|
||||||
user_update_parser.add_argument('last_name', type=str, required=False, store_missing=False)
|
user_update_parser.add_argument('last_name', type=str, required=False, store_missing=False)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import os
|
|||||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
class Config():
|
class Config:
|
||||||
# SERVER_NAME = "ubkaps154.ubka.uni-karlsruhe.de:5443"
|
# SERVER_NAME = "ubkaps154.ubka.uni-karlsruhe.de:5443"
|
||||||
# SERVER_NAME = "localhost.dev"
|
# SERVER_NAME = "localhost.dev"
|
||||||
SERVER_NAME = "localhost:5443"
|
SERVER_NAME = "localhost:5443"
|
||||||
@@ -97,6 +97,9 @@ class Config():
|
|||||||
"password": "admin"}
|
"password": "admin"}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
ROLE_PERMISSION_MAPPINGS = {
|
||||||
|
"admin": ["ADMIN"]
|
||||||
|
}
|
||||||
|
|
||||||
class ProductionConfig(Config):
|
class ProductionConfig(Config):
|
||||||
DATABASE_URI = 'mysql://user@localhost/foo'
|
DATABASE_URI = 'mysql://user@localhost/foo'
|
||||||
|
|||||||
@@ -5,5 +5,6 @@ from backend.models.example_model import *
|
|||||||
from backend.models.user_model import *
|
from backend.models.user_model import *
|
||||||
from backend.models.post_model import *
|
from backend.models.post_model import *
|
||||||
from backend.models.recorder_model import *
|
from backend.models.recorder_model import *
|
||||||
|
from backend.models.access_control_model import *
|
||||||
from backend.models.room_model import *
|
from backend.models.room_model import *
|
||||||
from backend.models.virtual_command_model import *
|
from backend.models.virtual_command_model import *
|
||||||
|
|||||||
73
backend/models/access_control_model.py
Normal file
73
backend/models/access_control_model.py
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Models for lecture recorder
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
|
||||||
|
from sqlalchemy import MetaData, CheckConstraint
|
||||||
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from backend import db, app, login_manager
|
||||||
|
from backend.tools.scrape_rooms import scrape_rooms
|
||||||
|
|
||||||
|
metadata = MetaData()
|
||||||
|
|
||||||
|
|
||||||
|
class AccessControlEntry(db.Model):
|
||||||
|
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
|
||||||
|
created_at = db.Column(db.DateTime, nullable=False, default=datetime.utcnow())
|
||||||
|
name = db.Column(db.Unicode(127), unique=False, nullable=False)
|
||||||
|
url = db.Column(db.Unicode(2047), unique=False, nullable=True, default="")
|
||||||
|
|
||||||
|
required_permission_id = db.Column(db.Integer, db.ForeignKey('permission.id'))
|
||||||
|
required_permission = db.relationship('Permission', back_populates='access_control_entry')
|
||||||
|
|
||||||
|
__table_args__ = (
|
||||||
|
CheckConstraint('length(name) > 2',
|
||||||
|
name='name_min_length'),
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super(AccessControlEntry, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_by_name(name):
|
||||||
|
"""
|
||||||
|
Find ace by name
|
||||||
|
:param name:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return AccessControlEntry.query.filter(AccessControlEntry.name == name).first()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_all():
|
||||||
|
"""
|
||||||
|
Return all ace
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return AccessControlEntry.query.all()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return dict(id=self.id, name=self.name)
|
||||||
|
|
||||||
|
def toJSON(self):
|
||||||
|
return json.dumps(self.to_dict(), default=lambda o: o.__dict__,
|
||||||
|
sort_keys=True, indent=4)
|
||||||
|
|
||||||
|
|
||||||
|
def pre_fill_table():
|
||||||
|
a_es = {"url": "", }
|
||||||
|
access_entries = [AccessControlEntry(name=room['name'], number=room['room_number'],
|
||||||
|
building_name=room['building_name'], building_number=room['building_number']) for room in
|
||||||
|
a_es]
|
||||||
|
|
||||||
|
try:
|
||||||
|
db.session.bulk_save_objects(access_entries)
|
||||||
|
db.session.commit()
|
||||||
|
except IntegrityError as e:
|
||||||
|
db.session.rollback()
|
||||||
@@ -8,6 +8,7 @@ from sqlalchemy.orm import relation
|
|||||||
from sqlalchemy import MetaData
|
from sqlalchemy import MetaData
|
||||||
|
|
||||||
from backend import db, app, login_manager
|
from backend import db, app, login_manager
|
||||||
|
from backend.config import Config
|
||||||
from backend.models.post_model import Post
|
from backend.models.post_model import Post
|
||||||
from backend.models.example_model import ExampleDataItem
|
from backend.models.example_model import ExampleDataItem
|
||||||
import re
|
import re
|
||||||
@@ -18,7 +19,6 @@ from datetime import datetime, timedelta
|
|||||||
from passlib.hash import sha256_crypt
|
from passlib.hash import sha256_crypt
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
|
|
||||||
|
|
||||||
metadata = MetaData()
|
metadata = MetaData()
|
||||||
|
|
||||||
followers = db.Table('followers',
|
followers = db.Table('followers',
|
||||||
@@ -34,31 +34,30 @@ acquaintances = db.Table('acquaintances',
|
|||||||
# This is the association table for the many-to-many relationship between
|
# This is the association table for the many-to-many relationship between
|
||||||
# groups and members - this is, the memberships.
|
# groups and members - this is, the memberships.
|
||||||
user_group_table = db.Table('user_group',
|
user_group_table = db.Table('user_group',
|
||||||
db.Column('user_id', db.Integer,
|
db.Column('user_id', db.Integer,
|
||||||
db.ForeignKey('user.id',
|
db.ForeignKey('user.id',
|
||||||
onupdate="CASCADE",
|
onupdate="CASCADE",
|
||||||
ondelete="CASCADE"),
|
ondelete="CASCADE"),
|
||||||
primary_key=True),
|
primary_key=True),
|
||||||
db.Column('group_id', db.Integer,
|
db.Column('group_id', db.Integer,
|
||||||
db.ForeignKey('group.id',
|
db.ForeignKey('group.id',
|
||||||
onupdate="CASCADE",
|
onupdate="CASCADE",
|
||||||
ondelete="CASCADE"),
|
ondelete="CASCADE"),
|
||||||
primary_key=True))
|
primary_key=True))
|
||||||
|
|
||||||
|
|
||||||
# This is the association table for the many-to-many relationship between
|
# This is the association table for the many-to-many relationship between
|
||||||
# groups and permissions.
|
# groups and permissions.
|
||||||
group_permission_table = db.Table('group_permission',
|
group_permission_table = db.Table('group_permission',
|
||||||
db.Column('group_id', db.Integer,
|
db.Column('group_id', db.Integer,
|
||||||
db.ForeignKey('group.id',
|
db.ForeignKey('group.id',
|
||||||
onupdate="CASCADE",
|
onupdate="CASCADE",
|
||||||
ondelete="CASCADE"),
|
ondelete="CASCADE"),
|
||||||
primary_key=True),
|
primary_key=True),
|
||||||
db.Column('permission_id', db.Integer,
|
db.Column('permission_id', db.Integer,
|
||||||
db.ForeignKey('permission.id',
|
db.ForeignKey('permission.id',
|
||||||
onupdate="CASCADE",
|
onupdate="CASCADE",
|
||||||
ondelete="CASCADE"),
|
ondelete="CASCADE"),
|
||||||
primary_key=True))
|
primary_key=True))
|
||||||
|
|
||||||
|
|
||||||
class User(UserMixin, db.Model):
|
class User(UserMixin, db.Model):
|
||||||
@@ -213,6 +212,16 @@ class User(UserMixin, db.Model):
|
|||||||
# TODO: implement correctly
|
# TODO: implement correctly
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def effective_permissions(self):
|
||||||
|
permissions = Config.ROLE_PERMISSION_MAPPINGS.get(self.role, [])
|
||||||
|
for g in self.groups:
|
||||||
|
print(g)
|
||||||
|
for p in g.permissions:
|
||||||
|
print(p)
|
||||||
|
permissions.append(p)
|
||||||
|
return permissions
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def decode_auth_token(auth_token):
|
def decode_auth_token(auth_token):
|
||||||
"""
|
"""
|
||||||
@@ -370,7 +379,7 @@ class User(UserMixin, db.Model):
|
|||||||
followers.c.follower_id == self.id).order_by(Post.timestamp.desc())
|
followers.c.follower_id == self.id).order_by(Post.timestamp.desc())
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
#return self.__dict__
|
# return self.__dict__
|
||||||
return dict(id=self.id, email=self.email, groups=[g.to_dict() for g in self.groups])
|
return dict(id=self.id, email=self.email, groups=[g.to_dict() for g in self.groups])
|
||||||
|
|
||||||
def toJSON(self):
|
def toJSON(self):
|
||||||
@@ -426,7 +435,6 @@ class Group(db.Model):
|
|||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
super(Group, self).__init__(**kwargs)
|
super(Group, self).__init__(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_by_name(name):
|
def get_by_name(name):
|
||||||
"""
|
"""
|
||||||
@@ -461,7 +469,8 @@ class Permission(db.Model):
|
|||||||
name = db.Column(db.Unicode(63), unique=True, nullable=False)
|
name = db.Column(db.Unicode(63), unique=True, nullable=False)
|
||||||
description = db.Column(db.Unicode(511))
|
description = db.Column(db.Unicode(511))
|
||||||
groups = db.relationship(Group, secondary=group_permission_table,
|
groups = db.relationship(Group, secondary=group_permission_table,
|
||||||
back_populates='permissions')
|
back_populates='permissions')
|
||||||
|
access_control_entry = db.relationship('AccessControlEntry', back_populates='required_permission')
|
||||||
|
|
||||||
|
|
||||||
@event.listens_for(User.__table__, 'after_create')
|
@event.listens_for(User.__table__, 'after_create')
|
||||||
|
|||||||
Reference in New Issue
Block a user