Move access permissions to access module
This commit is contained in:
@@ -22,13 +22,14 @@ from govoplan_access.backend.db.models import (
|
||||
)
|
||||
from govoplan_access.backend.semantic import ensure_identity_for_account
|
||||
from govoplan_access.backend.security.passwords import hash_password
|
||||
from govoplan_core.security.permissions import (
|
||||
DEFAULT_SYSTEM_ROLES,
|
||||
DEFAULT_TENANT_ROLES,
|
||||
from govoplan_access.backend.permissions.catalog import (
|
||||
delegateable_system_scopes,
|
||||
delegateable_tenant_scopes,
|
||||
normalize_email,
|
||||
scopes_grant,
|
||||
validate_system_permissions,
|
||||
validate_tenant_permissions,
|
||||
role_templates_for_level,
|
||||
)
|
||||
from govoplan_core.tenancy.service import tenant_counts # re-exported compatibility helper
|
||||
|
||||
@@ -48,21 +49,23 @@ def generate_temporary_password(length: int = 20) -> str:
|
||||
|
||||
|
||||
def ensure_default_roles(session: Session, tenant: Tenant | None = None) -> dict[str, Role]:
|
||||
definitions = DEFAULT_TENANT_ROLES if tenant is not None else DEFAULT_SYSTEM_ROLES
|
||||
level = "tenant" if tenant is not None else "system"
|
||||
roles: dict[str, Role] = {}
|
||||
for slug, definition in definitions.items():
|
||||
query = session.query(Role).filter(Role.slug == slug)
|
||||
for template in role_templates_for_level(level):
|
||||
query = session.query(Role).filter(Role.slug == template.slug)
|
||||
query = query.filter(Role.tenant_id == tenant.id) if tenant is not None else query.filter(Role.tenant_id.is_(None))
|
||||
role = query.one_or_none()
|
||||
is_builtin = _template_is_builtin(template_managed=template.managed, protected=template.protected, tenant_role=tenant is not None)
|
||||
is_assignable = True
|
||||
if role is None:
|
||||
role = Role(
|
||||
tenant_id=tenant.id if tenant is not None else None,
|
||||
slug=slug,
|
||||
name=str(definition["name"]),
|
||||
description=str(definition.get("description") or "") or None,
|
||||
permissions=list(definition["permissions"]),
|
||||
is_builtin=bool(definition.get("is_builtin", True)),
|
||||
is_assignable=bool(definition.get("is_assignable", True)),
|
||||
slug=template.slug,
|
||||
name=template.name,
|
||||
description=template.description or None,
|
||||
permissions=list(template.permissions),
|
||||
is_builtin=is_builtin,
|
||||
is_assignable=is_assignable,
|
||||
)
|
||||
session.add(role)
|
||||
session.flush()
|
||||
@@ -70,18 +73,30 @@ def ensure_default_roles(session: Session, tenant: Tenant | None = None) -> dict
|
||||
# Tenant built-ins and explicitly managed system roles remain
|
||||
# code-defined. Seeded, non-protected system roles are only created
|
||||
# here and can subsequently be administered in the System roles UI.
|
||||
managed = tenant is not None or bool(definition.get("managed", False))
|
||||
managed = _template_updates_existing(template_managed=template.managed, protected=template.protected, tenant_role=tenant is not None)
|
||||
if managed:
|
||||
role.name = str(definition["name"])
|
||||
role.description = str(definition.get("description") or "") or None
|
||||
role.permissions = list(definition["permissions"])
|
||||
role.is_builtin = bool(definition.get("is_builtin", True))
|
||||
role.is_assignable = bool(definition.get("is_assignable", True))
|
||||
role.name = template.name
|
||||
role.description = template.description or None
|
||||
role.permissions = list(template.permissions)
|
||||
role.is_builtin = is_builtin
|
||||
role.is_assignable = is_assignable
|
||||
session.add(role)
|
||||
roles[slug] = role
|
||||
roles[template.slug] = role
|
||||
return roles
|
||||
|
||||
|
||||
def _template_is_builtin(*, template_managed: bool, protected: bool, tenant_role: bool) -> bool:
|
||||
if tenant_role:
|
||||
return template_managed or protected
|
||||
return protected
|
||||
|
||||
|
||||
def _template_updates_existing(*, template_managed: bool, protected: bool, tenant_role: bool) -> bool:
|
||||
if tenant_role:
|
||||
return template_managed or protected
|
||||
return protected
|
||||
|
||||
|
||||
def get_or_create_account(
|
||||
session: Session,
|
||||
*,
|
||||
@@ -381,8 +396,6 @@ def delete_system_role(session: Session, role: Role) -> None:
|
||||
|
||||
def assert_can_delegate_system_permissions(actor_scopes: Iterable[str], permissions: Iterable[str]) -> None:
|
||||
"""Prevent a system administrator from defining stronger roles than they hold."""
|
||||
from govoplan_core.security.permissions import delegateable_system_scopes
|
||||
|
||||
requested = set(validate_system_permissions(permissions))
|
||||
if "system:*" in requested:
|
||||
if not scopes_grant(actor_scopes, "system:*"):
|
||||
@@ -546,7 +559,6 @@ def role_assignment_counts(session: Session, role_id: str) -> tuple[int, int]:
|
||||
|
||||
def assert_can_delegate_tenant_permissions(actor_scopes: Iterable[str], permissions: Iterable[str]) -> None:
|
||||
"""Prevent administrators from defining or assigning roles beyond their own effective tenant powers."""
|
||||
from govoplan_core.security.permissions import delegateable_tenant_scopes
|
||||
requested = set(validate_tenant_permissions(permissions))
|
||||
if "tenant:*" in requested:
|
||||
# Only a tenant owner-equivalent can delegate the wildcard.
|
||||
|
||||
Reference in New Issue
Block a user