feat(auth): sync Keycloak users for authorization
Generic Container CI/CD / test-build-publish (push) Failing after 33s
Server CI/CD v2 / build-test-publish-and-deploy (push) Failing after 34s

This commit is contained in:
2026-11-04 13:35:29 +08:00
parent bd8c619bfb
commit 9a9add1531
11 changed files with 716 additions and 8 deletions
@@ -5,6 +5,7 @@ from uuid import UUID, uuid4
from cryptography.fernet import InvalidToken
from sqlalchemy import delete, func, select
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.encryption import (
@@ -158,6 +159,44 @@ class MetadataRepository:
await self.session.refresh(user)
return user
async def sync_user_snapshot_from_keycloak(
self,
*,
keycloak_id: UUID,
username: str,
email: str,
) -> tuple[models.User, bool]:
user = await self.get_user_by_keycloak_id(keycloak_id)
if user is not None:
user.username = username
user.email = email
user.updated_at = _utcnow()
await self.session.commit()
await self.session.refresh(user)
return user, False
statement = (
insert(models.User)
.values(
id=uuid4(),
keycloak_id=keycloak_id,
username=username,
email=email,
role="user",
is_active=False,
is_superuser=False,
)
.on_conflict_do_nothing(index_elements=[models.User.keycloak_id])
.returning(models.User.id)
)
result = await self.session.execute(statement)
inserted_id = result.scalar_one_or_none()
await self.session.commit()
user = await self.get_user_by_keycloak_id(keycloak_id)
if user is None:
raise RuntimeError("Keycloak user synchronization did not persist a user")
return user, inserted_id is not None
async def refresh_user_keycloak_snapshot(
self,
user: models.User,