Implement perms system
Signed-off-by: Tiago Garcia <tiago.rgarcia@ua.pt>
This commit is contained in:
parent
ee825dcf39
commit
0ce6d25359
|
@ -5,15 +5,15 @@ class Organization(db_connection.Model):
|
|||
|
||||
id = db_connection.Column(db_connection.Integer, primary_key=True, index=True)
|
||||
name = db_connection.Column(db_connection.String, unique=True, index=True, nullable=False)
|
||||
roles = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
users = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
users_id = db_connection.Column(db_connection.Integer, db_connection.ForeignKey('users.id'))
|
||||
manager = db_connection.relationship('User', backref=db_connection.backref('owned_organization', uselist=False))
|
||||
|
||||
def to_dict(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"name": self.name,
|
||||
"manager": self.manager.to_dict(),
|
||||
"roles": [{"role": role, "permissions": permissions} for role, permissions in self.roles.items()],
|
||||
"users": [{"id": user_id, "user_data": {
|
||||
"username": user_data["username"],
|
||||
"full_name": user_data["full_name"],
|
||||
|
|
|
@ -9,6 +9,7 @@ class User(db_connection.Model):
|
|||
username = db_connection.Column(db_connection.String, unique=True, index=True, nullable=False)
|
||||
full_name = db_connection.Column(db_connection.String, nullable=False)
|
||||
email = db_connection.Column(db_connection.String, unique=True, index=True, nullable=False)
|
||||
roles = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
public_keys = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
orgs = db_connection.Column(db_connection.JSON, nullable=False, default=dict)
|
||||
|
||||
|
@ -18,5 +19,6 @@ class User(db_connection.Model):
|
|||
"username": self.username,
|
||||
"full_name": self.full_name,
|
||||
"email": self.email,
|
||||
"role": self.role,
|
||||
"orgs": [{"id": org_id, "name": org_data["name"], "status": org_data["status"]} for org_id, org_data in self.orgs.items()],
|
||||
}
|
|
@ -89,9 +89,6 @@ def user_create():
|
|||
if not org:
|
||||
return jsonify({"error": "Organization not found"}), 404
|
||||
|
||||
if org.manager.id != session.user_id:
|
||||
return jsonify({"error": "Not authorized to create users"}), 403
|
||||
|
||||
user = UserService.get_user_by_username(data["username"])
|
||||
if not user:
|
||||
user = UserService.create_user(
|
||||
|
@ -118,8 +115,6 @@ def user_suspend(username):
|
|||
org = OrganizationService.get_organization(session.org_id)
|
||||
if not org:
|
||||
return jsonify({"error": "Organization not found"}), 404
|
||||
if org.manager.id != session.user_id:
|
||||
return jsonify({"error": "Not authorized to suspend users"}), 403
|
||||
|
||||
user = UserService.get_user_by_username(username)
|
||||
if not user:
|
||||
|
@ -141,8 +136,6 @@ def user_unsuspend(username):
|
|||
org = OrganizationService.get_organization(session.org_id)
|
||||
if not org:
|
||||
return jsonify({"error": "Organization not found"}), 404
|
||||
if org.manager.id != session.user_id:
|
||||
return jsonify({"error": "Not authorized to unsuspend users"}), 403
|
||||
|
||||
user = UserService.get_user_by_username(username)
|
||||
if not user:
|
||||
|
|
|
@ -3,6 +3,7 @@ import os.path
|
|||
from database import db
|
||||
from models import Organization, User
|
||||
from sqlalchemy.orm.attributes import flag_modified
|
||||
from utils.perms import Perm
|
||||
|
||||
|
||||
class OrganizationService:
|
||||
|
@ -18,9 +19,33 @@ class OrganizationService:
|
|||
if not os.path.exists(os.path.join(repos, name)):
|
||||
os.mkdir(os.path.join(repos, name))
|
||||
|
||||
roles = {
|
||||
"manager": {
|
||||
"permissions": Perm.get_int([
|
||||
Perm.DOC_ACL,
|
||||
Perm.DOC_READ,
|
||||
Perm.DOC_DELETE,
|
||||
Perm.ROLE_ACL,
|
||||
Perm.SUBJECT_NEW,
|
||||
Perm.SUBJECT_DOWN,
|
||||
Perm.SUBJECT_UP,
|
||||
Perm.DOC_NEW,
|
||||
Perm.ROLE_NEW,
|
||||
Perm.ROLE_DOWN,
|
||||
Perm.ROLE_UP,
|
||||
Perm.ROLE_MOD
|
||||
]),
|
||||
"users": [user.id]
|
||||
},
|
||||
"default": {
|
||||
"permissions": Perm.get_int([]),
|
||||
"users": []
|
||||
}
|
||||
}
|
||||
|
||||
organization = Organization(
|
||||
name=name,
|
||||
manager=user,
|
||||
roles=roles,
|
||||
users={user.id: {
|
||||
"username": user.username,
|
||||
"full_name": user.full_name,
|
||||
|
@ -34,6 +59,7 @@ class OrganizationService:
|
|||
db.refresh(organization)
|
||||
|
||||
UserService().add_org_to_user(user, organization)
|
||||
UserService().add_role_to_user(user, organization, "manager")
|
||||
UserService().add_public_key_to_user(user, organization, public_key)
|
||||
|
||||
return organization
|
||||
|
@ -71,12 +97,40 @@ class OrganizationService:
|
|||
db.refresh(org)
|
||||
return org
|
||||
|
||||
@staticmethod
|
||||
def create_role(org: Organization, role: str, perms: list[Perm]) -> Organization:
|
||||
roles = org.roles.copy()
|
||||
roles[role] = {
|
||||
"permissions": Perm.get_int(perms),
|
||||
"users": []
|
||||
}
|
||||
org.roles = roles
|
||||
flag_modified(org, "roles")
|
||||
db.commit()
|
||||
db.refresh(org)
|
||||
return org
|
||||
|
||||
@staticmethod
|
||||
def delete_role(org: Organization, role: str) -> Organization:
|
||||
roles = org.roles.copy()
|
||||
del roles[role]
|
||||
org.roles = roles
|
||||
flag_modified(org, "roles")
|
||||
db.commit()
|
||||
db.refresh(org)
|
||||
return org
|
||||
|
||||
@staticmethod
|
||||
def check_role_permission(org: Organization, role: str, perm: Perm) -> bool:
|
||||
role_perms = org.roles[role]["permissions"]
|
||||
return Perm.check_perm(role_perms, perm.value)
|
||||
|
||||
@staticmethod
|
||||
def suspend_user(org: Organization, user: User) -> tuple:
|
||||
if OrganizationService.get_user_status(org, user.id) != "active":
|
||||
return {"error": "User already suspended"}, 400
|
||||
|
||||
if org.manager.id == user.id:
|
||||
if user.roles[org.id] == "manager":
|
||||
return {"error": "Cannot suspend manager"}, 400
|
||||
|
||||
org.users[str(user.id)]["status"] = "suspended"
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
from sqlalchemy.orm.attributes import flag_modified
|
||||
|
||||
from database import db
|
||||
from models import User, Organization
|
||||
|
||||
|
@ -10,6 +12,7 @@ class UserService:
|
|||
username=username,
|
||||
full_name=full_name,
|
||||
email=email,
|
||||
roles={},
|
||||
public_keys={org.id: public_key} if org else {},
|
||||
orgs={org.id: {
|
||||
"name": org.name,
|
||||
|
@ -43,6 +46,40 @@ class UserService:
|
|||
db.refresh(user)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def add_role_to_user(user: User, org: Organization, role: str) -> User:
|
||||
roles = user.roles.copy()
|
||||
roles[org.id] = role
|
||||
user.roles = roles
|
||||
flag_modified(user, "roles")
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
|
||||
roles = org.roles.copy()
|
||||
roles[role]["users"].append(user.id)
|
||||
org.roles = roles
|
||||
flag_modified(org, "roles")
|
||||
db.commit()
|
||||
db.refresh(org)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def remove_role_from_user(user: User, org: Organization, role: str) -> User:
|
||||
roles = user.roles.copy()
|
||||
roles.pop(org.id)
|
||||
user.roles = roles
|
||||
flag_modified(user, "roles")
|
||||
db.commit()
|
||||
db.refresh(user)
|
||||
|
||||
roles = org.roles.copy()
|
||||
roles[role]["users"].remove(user.id)
|
||||
org.roles = roles
|
||||
flag_modified(org, "roles")
|
||||
db.commit()
|
||||
db.refresh(org)
|
||||
return user
|
||||
|
||||
@staticmethod
|
||||
def add_public_key_to_user(user: User, org: Organization, public_key: str) -> User:
|
||||
public_keys = user.public_keys.copy()
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
from enum import Enum
|
||||
|
||||
|
||||
class Perm(Enum):
|
||||
DOC_ACL = 0b000000000001
|
||||
DOC_READ = 0b000000000010
|
||||
DOC_DELETE = 0b000000000100
|
||||
ROLE_ACL = 0b000000001000
|
||||
SUBJECT_NEW = 0b000000010000
|
||||
SUBJECT_DOWN = 0b000000100000
|
||||
SUBJECT_UP = 0b000001000000
|
||||
DOC_NEW = 0b000010000000
|
||||
ROLE_NEW = 0b000100000000
|
||||
ROLE_DOWN = 0b001000000000
|
||||
ROLE_UP = 0b010000000000
|
||||
ROLE_MOD = 0b100000000000
|
||||
|
||||
@staticmethod
|
||||
def get_perm(bit_array: int):
|
||||
for perm in Perm:
|
||||
if bit_array == perm.value:
|
||||
return perm
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_int(perms):
|
||||
if isinstance(perms, list):
|
||||
return sum([p.value for p in perms if isinstance(p, Perm)])
|
||||
return perms.value if isinstance(perms, Perm) else 0
|
||||
|
||||
@staticmethod
|
||||
def check_perm(perm, bit_array: int):
|
||||
return perm.value & bit_array == perm.value
|
Loading…
Reference in New Issue