Orgs can only grant permissions to groups that they themselves have been granted access to. Super admin bypasses not added, flagged as todos.
This commit is contained in:
parent
0a867c9c90
commit
662b9c8e26
6 changed files with 71 additions and 4 deletions
38
.alembic/versions/2026-06-16_org_perm_perms_join_table.py
Normal file
38
.alembic/versions/2026-06-16_org_perm_perms_join_table.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"""org perm perms join table
|
||||
|
||||
Revision ID: 85edbf9a176c
|
||||
Revises: 98e20aae555c
|
||||
Create Date: 2026-06-16 13:31:57.427953
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '85edbf9a176c'
|
||||
down_revision: Union[str, Sequence[str], None] = '98e20aae555c'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.create_table('org_permissions',
|
||||
sa.Column('org_id', sa.Integer(), nullable=False),
|
||||
sa.Column('permission_id', sa.Integer(), nullable=False),
|
||||
sa.ForeignKeyConstraint(['org_id'], ['organisation.id'], ondelete='CASCADE'),
|
||||
sa.ForeignKeyConstraint(['permission_id'], ['permission.id'], ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('org_id', 'permission_id')
|
||||
)
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.drop_table('org_permissions')
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -52,6 +52,10 @@ class Permission(Base):
|
|||
"Group", secondary="group_permissions", back_populates="permission_rel"
|
||||
)
|
||||
|
||||
org_rel = relationship(
|
||||
"Organisation", secondary="org_permissions", back_populates="permission_rel"
|
||||
)
|
||||
|
||||
|
||||
class Group(Base):
|
||||
__tablename__ = "group"
|
||||
|
|
@ -95,3 +99,13 @@ class UserGroups(Base):
|
|||
group_id = Column(
|
||||
Integer, ForeignKey("group.id", ondelete="CASCADE"), primary_key=True
|
||||
)
|
||||
|
||||
|
||||
class OrgPermissions(Base):
|
||||
__tablename__ = "org_permissions"
|
||||
org_id = Column(
|
||||
Integer, ForeignKey("organisation.id", ondelete="CASCADE"), primary_key=True
|
||||
)
|
||||
permission_id = Column(
|
||||
Integer, ForeignKey("permission.id", ondelete="CASCADE"), primary_key=True
|
||||
)
|
||||
|
|
|
|||
|
|
@ -325,6 +325,9 @@ async def add_group_permission(
|
|||
if perm_model in group_model.permission_rel:
|
||||
raise ConflictException("Group already has this permission")
|
||||
|
||||
if perm_model not in org_model.permission_rel: # TODO: and not su
|
||||
raise ForbiddenException("You cannot grant this permission")
|
||||
|
||||
group_model.permission_rel.append(perm_model)
|
||||
|
||||
db.flush()
|
||||
|
|
@ -471,8 +474,10 @@ async def get_permissions(
|
|||
"""
|
||||
Returns a full list of permissions.
|
||||
"""
|
||||
permission_models = db.query(Perm).all()
|
||||
|
||||
# TODO: if su:
|
||||
# permission_models = db.query(Perm).all()
|
||||
# else
|
||||
permission_models = db.query(Perm).filter(Perm.org_rel.any(id=org_model.id)).all()
|
||||
return {"permissions": permission_models}
|
||||
|
||||
|
||||
|
|
@ -566,6 +571,9 @@ async def post_permissions(
|
|||
if not (request_model.action is None or request_model.action == ""):
|
||||
permission_query = permission_query.filter(Perm.action == request_model.action)
|
||||
|
||||
# TODO: if not su:
|
||||
permission_query = permission_query.filter(Perm.org_rel.any(id=org_model.id))
|
||||
|
||||
permission_models = permission_query.all()
|
||||
|
||||
return {"permissions": permission_models}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ class Organisation(Base):
|
|||
"Contact", foreign_keys="Organisation.owner_contact_id"
|
||||
)
|
||||
|
||||
permission_rel = relationship(
|
||||
"Permission", secondary="org_permissions", back_populates="org_rel"
|
||||
)
|
||||
|
||||
|
||||
class OrgUsers(Base):
|
||||
__tablename__ = "orgusers"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ from src.user.models import User
|
|||
from src.service.models import Service
|
||||
from src.organisation.models import Organisation as Org, OrgUsers
|
||||
from src.contact.models import Contact
|
||||
from src.iam.models import Group, Permission
|
||||
from src.iam.models import Group, Permission, OrgPermissions
|
||||
from src.auth.service import get_current_user, get_dev_user
|
||||
from src.auth.dependencies import empty_su_list, get_super_admin_list, testing_su_list
|
||||
from src.main import app # inited FastAPI app
|
||||
|
|
@ -163,6 +163,9 @@ def _seed(db):
|
|||
db.add(Service(name="Test Service", api_key="123456789"))
|
||||
db.add(Permission(service_id=1, resource="test_resource", action="read"))
|
||||
db.add(Permission(service_id=1, resource="test_resource", action="move"))
|
||||
db.add(Permission(service_id=1, resource="test_resource", action="delete"))
|
||||
db.add(OrgPermissions(org_id=1, permission_id=1))
|
||||
db.add(OrgPermissions(org_id=1, permission_id=2))
|
||||
db.add(Group(name="Org One Group", org_id=1))
|
||||
db.add(Group(name="Org Two Group", org_id=2))
|
||||
db.add(Group(name="Org One Group Two", org_id=1))
|
||||
|
|
|
|||
|
|
@ -437,7 +437,7 @@ async def test_post_perm_success(default_client: AsyncClient):
|
|||
assert "permission" in data
|
||||
assert isinstance(data["permission"], dict)
|
||||
|
||||
assert data["permission"]["id"] == 3
|
||||
assert data["permission"]["id"] == 4
|
||||
assert data["permission"]["service_name"] == "Test Service"
|
||||
assert data["permission"]["resource"] == "test_resource"
|
||||
assert data["permission"]["action"] == "create"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue