intermittent commit

This commit is contained in:
2026-07-14 13:22:09 +02:00
parent f2afcaa09c
commit ab07075a67
17 changed files with 1821 additions and 586 deletions

View File

@@ -2,6 +2,7 @@ from __future__ import annotations
from dataclasses import dataclass
from datetime import timedelta
from collections.abc import Iterable
from sqlalchemy.orm import Session
@@ -18,7 +19,7 @@ from govoplan_access.backend.db.models import (
UserGroupMembership,
UserRoleAssignment,
)
from govoplan_access.backend.semantic import collect_function_roles
from govoplan_access.backend.semantic import collect_function_authorization_context, collect_function_roles
from govoplan_access.backend.permissions.catalog import expand_scopes
from govoplan_core.security.time import ensure_aware_utc, utc_now
@@ -33,6 +34,16 @@ class CreatedSession:
csrf_token: str
@dataclass(slots=True)
class UserAuthorizationContext:
tenant_roles: list[Role]
system_roles: list[Role]
groups: list[Group]
function_assignment_ids: tuple[str, ...]
function_delegation_ids: tuple[str, ...]
scopes: list[str]
def generate_session_token() -> str:
return generate_secret("ms_", random_bytes=SESSION_RANDOM_BYTES)
@@ -199,6 +210,56 @@ def collect_user_groups(session: Session, user: User) -> list[Group]:
)
def collect_user_authorization_context(
session: Session,
user: User,
*,
account: Account | None = None,
include_system: bool = True,
extra_roles: Iterable[Role] = (),
) -> UserAuthorizationContext:
account = account or user.account
roles_by_id: dict[str, Role] = {role.id: role for role in collect_direct_user_roles(session, user)}
groups = collect_user_groups(session, user)
group_ids = [group.id for group in groups]
if group_ids:
group_roles = (
session.query(Role)
.join(GroupRoleAssignment, GroupRoleAssignment.role_id == Role.id)
.filter(
GroupRoleAssignment.tenant_id == user.tenant_id,
GroupRoleAssignment.group_id.in_(sorted(group_ids)),
Role.tenant_id == user.tenant_id,
)
.order_by(Role.name.asc())
.all()
)
for role in group_roles:
roles_by_id[role.id] = role
function_context = collect_function_authorization_context(session, user)
for role in function_context.roles:
roles_by_id[role.id] = role
for role in extra_roles:
roles_by_id[role.id] = role
tenant_roles = list(roles_by_id.values())
system_roles = collect_system_roles(session, account) if include_system and account is not None else []
scopes = {
scope
for role in [*tenant_roles, *system_roles]
for scope in (role.permissions or [])
}
return UserAuthorizationContext(
tenant_roles=tenant_roles,
system_roles=system_roles,
groups=groups,
function_assignment_ids=function_context.assignment_ids,
function_delegation_ids=function_context.delegation_ids,
scopes=expand_scopes(scopes),
)
def collect_user_scopes(session: Session, user: User, *, include_system: bool = True) -> list[str]:
scopes: set[str] = set()
for role in collect_user_roles(session, user):