Fix file permission system
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
This commit is contained in:
parent
5e21a77c5d
commit
8033aa9d60
|
@ -9,6 +9,8 @@ class File(db_connection.Model):
|
|||
document_handle = db_connection.Column(db_connection.String, unique=True, nullable=False)
|
||||
name = db_connection.Column(db_connection.String, nullable=False)
|
||||
created_at = db_connection.Column(db_connection.Integer, nullable=False)
|
||||
acl = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
deleter_id = db_connection.Column(db_connection.Integer, nullable=True)
|
||||
key = db_connection.Column(db_connection.String, nullable=False)
|
||||
alg = db_connection.Column(db_connection.String, nullable=False)
|
||||
org_id = db_connection.Column(db_connection.Integer, db_connection.ForeignKey('organizations.id'), nullable=False)
|
||||
|
@ -23,8 +25,10 @@ class File(db_connection.Model):
|
|||
"document_handle": self.document_handle,
|
||||
"name": self.name,
|
||||
"created_at": self.created_at,
|
||||
"acl": self.acl,
|
||||
"key": self.key,
|
||||
"alg": self.alg,
|
||||
"org": {"id": self.org.id, "name": self.org.name},
|
||||
"creator": {"id": self.creator.id, "username": self.creator.username}
|
||||
"creator": {"id": self.creator.id, "username": self.creator.username},
|
||||
"deleter": {"id": self.deleter.id, "username": self.deleter.username} if self.deleter else None
|
||||
}
|
|
@ -22,7 +22,7 @@ def file_get_content(file_handle: str):
|
|||
@file_bp.route("/get/<string:document_handle>/metadata", methods=["GET"])
|
||||
def file_get_metadata(document_handle: str):
|
||||
session_token = request.headers.get("Authorization")
|
||||
session = SessionService.validate_session(session_token, required_perms=[Perm.DOC_READ])
|
||||
session = SessionService.validate_session(session_token, required_perms=[Perm.DOC_READ], doc_handle=document_handle)
|
||||
if isinstance(session, tuple):
|
||||
return session
|
||||
|
||||
|
@ -145,7 +145,7 @@ def file_delete(document_handle: str):
|
|||
if not session_token:
|
||||
return jsonify({"error": "No session token"}), 400
|
||||
|
||||
session = SessionService.validate_session(session_token, required_perms=[Perm.DOC_DELETE])
|
||||
session = SessionService.validate_session(session_token, required_perms=[Perm.DOC_DELETE], doc_handle=document_handle)
|
||||
if isinstance(session, tuple):
|
||||
return session
|
||||
|
||||
|
@ -160,7 +160,7 @@ def file_delete(document_handle: str):
|
|||
if file.creator_id != session.user_id:
|
||||
return jsonify({"error": "Not authorized to delete file"}), 403
|
||||
|
||||
file = FileService.delete_file(file)
|
||||
file = FileService.delete_file(file, session.user_id)
|
||||
return jsonify(file.to_dict())
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from flask import jsonify
|
|||
|
||||
from database import db
|
||||
from models import File, Organization, User
|
||||
from utils import get_hash
|
||||
from utils import get_hash, Perm
|
||||
|
||||
|
||||
class FileService:
|
||||
|
@ -19,10 +19,18 @@ class FileService:
|
|||
document_handle = get_hash(file_name),
|
||||
name = file_name,
|
||||
created_at = int(datetime.now().timestamp()),
|
||||
acl = {
|
||||
"manager": Perm.get_int([
|
||||
Perm.DOC_ACL,
|
||||
Perm.DOC_READ,
|
||||
Perm.DOC_DELETE,
|
||||
])
|
||||
},
|
||||
key = key,
|
||||
alg = alg,
|
||||
org_id = org.id,
|
||||
creator_id = user.id,
|
||||
deleter_id = None,
|
||||
org = org,
|
||||
creator = user
|
||||
)
|
||||
|
@ -101,10 +109,11 @@ class FileService:
|
|||
return db.query(File).filter(File.org_id == org.id).all()
|
||||
|
||||
@staticmethod
|
||||
def delete_file(file: File) -> File:
|
||||
def delete_file(file: File, deleter_id: int) -> File:
|
||||
file_path = os.path.join(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "repository"), file.org.name, file.document_handle)
|
||||
os.remove(file_path)
|
||||
file.file_handle = None
|
||||
file.deleter_id = deleter_id
|
||||
db.commit()
|
||||
db.refresh(file)
|
||||
return file
|
|
@ -24,9 +24,6 @@ class OrganizationService:
|
|||
roles = {
|
||||
"manager": {
|
||||
"permissions": Perm.get_int([
|
||||
Perm.DOC_ACL,
|
||||
Perm.DOC_READ,
|
||||
Perm.DOC_DELETE,
|
||||
Perm.ROLE_ACL,
|
||||
Perm.SUBJECT_NEW,
|
||||
Perm.SUBJECT_DOWN,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from database import db
|
||||
from models import Organization, User
|
||||
from models import Organization, User, File
|
||||
from sqlalchemy.orm.attributes import flag_modified
|
||||
from utils import Perm
|
||||
|
||||
|
@ -74,7 +74,22 @@ class RoleService:
|
|||
return org.roles[role]
|
||||
|
||||
@staticmethod
|
||||
def check_role_permission(org: Organization, role: str, perm: Perm) -> bool:
|
||||
def check_role_permission(org: Organization, role: str, perm: Perm, doc_handle=None) -> bool:
|
||||
from services import FileService
|
||||
|
||||
if doc_handle:
|
||||
file = FileService.get_file_by_document_handle(doc_handle)
|
||||
if not file:
|
||||
raise ValueError(f"Document {doc_handle} not found")
|
||||
|
||||
if not Perm.check_perm(file.acl[role], perm.value):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
if role not in org.roles:
|
||||
raise ValueError(f"Role {role} does not exist in organization {org.name}")
|
||||
|
||||
role_perms = org.roles[role]["permissions"]
|
||||
return Perm.check_perm(role_perms, perm.value)
|
||||
|
||||
|
@ -163,6 +178,9 @@ class RoleService:
|
|||
|
||||
@staticmethod
|
||||
def add_perm_to_role(org: Organization, role: str, perm: Perm) -> dict:
|
||||
if perm in [Perm.DOC_ACL, Perm.DOC_READ, Perm.DOC_DELETE]:
|
||||
raise ValueError(f"Permission {perm} is not allowed for organization's roles")
|
||||
|
||||
if role not in org.roles:
|
||||
raise ValueError(f"Role {role} does not exist in organization {org.name}")
|
||||
|
||||
|
@ -179,6 +197,9 @@ class RoleService:
|
|||
|
||||
@staticmethod
|
||||
def remove_perm_from_role(org: Organization, role: str, perm: Perm) -> dict:
|
||||
if perm in [Perm.DOC_ACL, Perm.DOC_READ, Perm.DOC_DELETE]:
|
||||
raise ValueError(f"Permission {perm} is not allowed for organization's roles")
|
||||
|
||||
if role not in org.roles:
|
||||
raise ValueError(f"Role {role} does not exist in organization {org.name}")
|
||||
|
||||
|
@ -192,3 +213,37 @@ class RoleService:
|
|||
db.commit()
|
||||
db.refresh(org)
|
||||
return org.roles[role]
|
||||
|
||||
@staticmethod
|
||||
def add_perm_to_role_in_file(file: File, role: str, perm: Perm) -> dict:
|
||||
if perm not in [Perm.DOC_ACL, Perm.DOC_READ, Perm.DOC_DELETE]:
|
||||
raise ValueError(f"Permission {perm} is not allowed for files' roles")
|
||||
|
||||
if role not in file.acl:
|
||||
file.acl[role] = 0
|
||||
|
||||
if file.acl[role] & perm.value != 0:
|
||||
raise ValueError(f"Role {role} already has permission {perm} in file {file.document_handle}")
|
||||
|
||||
file.acl[role] |= perm.value
|
||||
flag_modified(file, "acl")
|
||||
db.commit()
|
||||
db.refresh(file)
|
||||
return file.acl
|
||||
|
||||
@staticmethod
|
||||
def remove_perm_from_role_in_file(file: File, role: str, perm: Perm) -> dict:
|
||||
if perm not in [Perm.DOC_ACL, Perm.DOC_READ, Perm.DOC_DELETE]:
|
||||
raise ValueError(f"Permission {perm} is not allowed for files' roles")
|
||||
|
||||
if role not in file.acl:
|
||||
file.acl[role] = 0
|
||||
|
||||
if file.acl[role] & perm.value == 0:
|
||||
raise ValueError(f"Role {role} does not have permission {perm} in file {file.document_handle}")
|
||||
|
||||
file.acl[role] &= ~perm.value
|
||||
flag_modified(file, "acl")
|
||||
db.commit()
|
||||
db.refresh(file)
|
||||
return file.acl
|
|
@ -33,7 +33,7 @@ class SessionService:
|
|||
db.commit()
|
||||
|
||||
@staticmethod
|
||||
def validate_session(token: str, required_perms: list[Perm] = None) -> tuple | Session:
|
||||
def validate_session(token: str, required_perms: list[Perm] = None, doc_handle=None) -> tuple | Session:
|
||||
from services import OrganizationService
|
||||
|
||||
if "Bearer" in token:
|
||||
|
@ -53,7 +53,7 @@ class SessionService:
|
|||
|
||||
if required_perms:
|
||||
for perm in required_perms:
|
||||
if not SessionService.check_permission(session, perm):
|
||||
if not SessionService.check_permission(session, perm, doc_handle):
|
||||
return jsonify({"error": f"Permission denied, missing required permission: {perm}"}), 403
|
||||
|
||||
return session
|
||||
|
@ -111,7 +111,7 @@ class SessionService:
|
|||
return session.roles
|
||||
|
||||
@staticmethod
|
||||
def check_permission(session: Session, perm: Perm) -> bool:
|
||||
def check_permission(session: Session, perm: Perm, doc_handle=None) -> bool:
|
||||
from services import OrganizationService, RoleService
|
||||
|
||||
org = OrganizationService.get_organization(session.org_id)
|
||||
|
@ -123,7 +123,7 @@ class SessionService:
|
|||
return False
|
||||
|
||||
for role in session.roles:
|
||||
if RoleService.check_role_permission(org, role, perm):
|
||||
if RoleService.check_role_permission(org, role, perm, doc_handle):
|
||||
return True
|
||||
|
||||
return False
|
Loading…
Reference in New Issue