refactor: rebuild backend around role-site authorization model
This commit is contained in:
@@ -3,11 +3,11 @@ from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.config import get_settings
|
||||
from app.db.session import get_db
|
||||
from app.repositories.permissions_repo import PermissionsRepository
|
||||
from app.schemas.internal import InternalUpsertUserBySubResponse
|
||||
from app.repositories.users_repo import UsersRepository
|
||||
from app.repositories.user_sites_repo import UserSitesRepository
|
||||
from app.schemas.idp_admin import KeycloakEnsureUserRequest, KeycloakEnsureUserResponse
|
||||
from app.schemas.permissions import PermissionSnapshotResponse
|
||||
from app.schemas.internal import InternalUpsertUserBySubResponse, InternalUserRoleItem, InternalUserRoleResponse
|
||||
from app.schemas.permissions import RoleSnapshotResponse
|
||||
from app.schemas.users import UserUpsertBySubRequest
|
||||
from app.security.api_client_auth import require_api_client
|
||||
from app.services.idp_admin_service import KeycloakAdminService
|
||||
@@ -28,32 +28,84 @@ def upsert_user_by_sub(
|
||||
email=payload.email,
|
||||
display_name=payload.display_name,
|
||||
is_active=payload.is_active,
|
||||
status=payload.status,
|
||||
)
|
||||
return InternalUpsertUserBySubResponse(
|
||||
id=user.id,
|
||||
user_sub=user.user_sub,
|
||||
idp_user_id=user.idp_user_id,
|
||||
username=user.username,
|
||||
email=user.email,
|
||||
display_name=user.display_name,
|
||||
is_active=user.is_active,
|
||||
status=user.status,
|
||||
)
|
||||
return {
|
||||
"id": user.id,
|
||||
"user_sub": user.user_sub,
|
||||
"idp_user_id": user.idp_user_id,
|
||||
"username": user.username,
|
||||
"email": user.email,
|
||||
"display_name": user.display_name,
|
||||
"is_active": user.is_active,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/permissions/{user_sub}/snapshot", response_model=PermissionSnapshotResponse)
|
||||
def get_permission_snapshot(
|
||||
user_sub: str,
|
||||
db: Session = Depends(get_db),
|
||||
) -> PermissionSnapshotResponse:
|
||||
def _build_user_role_rows(db: Session, user_sub: str) -> list[tuple[str, str, str, str, str, str, str, str, str]]:
|
||||
users_repo = UsersRepository(db)
|
||||
perms_repo = PermissionsRepository(db)
|
||||
user_sites_repo = UserSitesRepository(db)
|
||||
|
||||
user = users_repo.get_by_sub(user_sub)
|
||||
if user is None:
|
||||
return PermissionSnapshotResponse(user_sub=user_sub, permissions=[])
|
||||
return []
|
||||
|
||||
permissions = perms_repo.list_by_user(user.id, user.user_sub)
|
||||
return PermissionService.build_snapshot(user_sub=user_sub, permissions=permissions)
|
||||
rows = user_sites_repo.get_user_role_rows(user.id)
|
||||
return [
|
||||
(
|
||||
site.site_key,
|
||||
site.display_name,
|
||||
company.company_key,
|
||||
company.display_name,
|
||||
system.system_key,
|
||||
system.name,
|
||||
role.role_key,
|
||||
role.name,
|
||||
role.idp_role_name,
|
||||
)
|
||||
for site, company, role, system in rows
|
||||
]
|
||||
|
||||
|
||||
@router.get("/users/{user_sub}/roles", response_model=InternalUserRoleResponse)
|
||||
def get_user_roles(user_sub: str, db: Session = Depends(get_db)) -> InternalUserRoleResponse:
|
||||
rows = _build_user_role_rows(db, user_sub)
|
||||
return InternalUserRoleResponse(
|
||||
user_sub=user_sub,
|
||||
roles=[
|
||||
InternalUserRoleItem(
|
||||
site_key=site_key,
|
||||
site_display_name=site_display_name,
|
||||
company_key=company_key,
|
||||
company_display_name=company_display_name,
|
||||
system_key=system_key,
|
||||
system_name=system_name,
|
||||
role_key=role_key,
|
||||
role_name=role_name,
|
||||
idp_role_name=idp_role_name,
|
||||
)
|
||||
for (
|
||||
site_key,
|
||||
site_display_name,
|
||||
company_key,
|
||||
company_display_name,
|
||||
system_key,
|
||||
system_name,
|
||||
role_key,
|
||||
role_name,
|
||||
idp_role_name,
|
||||
) in rows
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/permissions/{user_sub}/snapshot", response_model=RoleSnapshotResponse)
|
||||
def get_permission_snapshot(
|
||||
user_sub: str,
|
||||
db: Session = Depends(get_db),
|
||||
) -> RoleSnapshotResponse:
|
||||
rows = _build_user_role_rows(db, user_sub)
|
||||
return PermissionService.build_role_snapshot(user_sub=user_sub, rows=rows)
|
||||
|
||||
|
||||
@router.post("/idp/users/ensure", response_model=KeycloakEnsureUserResponse)
|
||||
@@ -73,17 +125,17 @@ def ensure_idp_user(
|
||||
)
|
||||
|
||||
users_repo = UsersRepository(db)
|
||||
resolved_sub = payload.user_sub or ""
|
||||
if sync_result.user_sub:
|
||||
resolved_sub = sync_result.user_sub
|
||||
resolved_sub = payload.user_sub or sync_result.user_sub or ""
|
||||
if not resolved_sub:
|
||||
raise HTTPException(status_code=status.HTTP_502_BAD_GATEWAY, detail="idp_missing_sub")
|
||||
|
||||
users_repo.upsert_by_sub(
|
||||
user_sub=resolved_sub,
|
||||
username=payload.username,
|
||||
email=payload.email,
|
||||
display_name=payload.display_name,
|
||||
is_active=payload.is_active,
|
||||
status="active",
|
||||
idp_user_id=sync_result.user_id,
|
||||
)
|
||||
return KeycloakEnsureUserResponse(idp_user_id=sync_result.user_id, action=sync_result.action)
|
||||
|
||||
Reference in New Issue
Block a user