Fix PocketID config lookup when multiple admins exist
_get_pocketid_config / _get_allowed_group selected an admin row with an unordered LIMIT 1. With more than one admin (e.g. the seeded password admin plus a passkey-linked admin), this non-deterministically returned an admin without PocketID config — making the passkey button disappear (available=false) and group gating inconsistent. Add _config_admin() which prefers the admin that actually has an issuer set, then falls back to the lowest-id admin. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+25
-4
@@ -14,10 +14,32 @@ from app.models.user import User
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
async def _config_admin(db: AsyncSession):
|
||||||
|
"""The admin row that holds instance-wide PocketID settings.
|
||||||
|
|
||||||
|
Settings live on an admin user row, but there can be more than one admin.
|
||||||
|
Prefer the admin that actually has an issuer configured; otherwise fall back
|
||||||
|
to the lowest-id admin. Without this, an unordered LIMIT 1 could return an
|
||||||
|
admin with no config and make PocketID look disabled / gating inconsistent.
|
||||||
|
"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(User)
|
||||||
|
.where(User.is_admin == True, User.pocketid_issuer.isnot(None))
|
||||||
|
.order_by(User.id)
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
admin = result.scalar_one_or_none()
|
||||||
|
if admin is None:
|
||||||
|
result = await db.execute(
|
||||||
|
select(User).where(User.is_admin == True).order_by(User.id).limit(1)
|
||||||
|
)
|
||||||
|
admin = result.scalar_one_or_none()
|
||||||
|
return admin
|
||||||
|
|
||||||
|
|
||||||
async def _get_pocketid_config(db: AsyncSession):
|
async def _get_pocketid_config(db: AsyncSession):
|
||||||
"""Get PocketID config from DB (admin user) falling back to env vars."""
|
"""Get PocketID config from DB (admin user) falling back to env vars."""
|
||||||
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
|
admin = await _config_admin(db)
|
||||||
admin = result.scalar_one_or_none()
|
|
||||||
issuer = (admin and admin.pocketid_issuer) or settings.pocketid_issuer
|
issuer = (admin and admin.pocketid_issuer) or settings.pocketid_issuer
|
||||||
client_id = (admin and admin.pocketid_client_id) or settings.pocketid_client_id
|
client_id = (admin and admin.pocketid_client_id) or settings.pocketid_client_id
|
||||||
client_secret = (admin and admin.pocketid_client_secret) or settings.pocketid_client_secret
|
client_secret = (admin and admin.pocketid_client_secret) or settings.pocketid_client_secret
|
||||||
@@ -26,8 +48,7 @@ async def _get_pocketid_config(db: AsyncSession):
|
|||||||
|
|
||||||
async def _get_allowed_group(db: AsyncSession):
|
async def _get_allowed_group(db: AsyncSession):
|
||||||
"""Group a PocketID user must belong to in order to sign in (None = allow all)."""
|
"""Group a PocketID user must belong to in order to sign in (None = allow all)."""
|
||||||
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
|
admin = await _config_admin(db)
|
||||||
admin = result.scalar_one_or_none()
|
|
||||||
group = (admin and admin.pocketid_allowed_group) or settings.pocketid_allowed_group
|
group = (admin and admin.pocketid_allowed_group) or settings.pocketid_allowed_group
|
||||||
return (group or "").strip() or None
|
return (group or "").strip() or None
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,32 @@ from app.models.user import User
|
|||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
async def _config_admin(db: AsyncSession):
|
||||||
|
"""The admin row that holds instance-wide PocketID settings.
|
||||||
|
|
||||||
|
Settings live on an admin user row, but there can be more than one admin.
|
||||||
|
Prefer the admin that actually has an issuer configured; otherwise fall back
|
||||||
|
to the lowest-id admin. Without this, an unordered LIMIT 1 could return an
|
||||||
|
admin with no config and make PocketID look disabled / gating inconsistent.
|
||||||
|
"""
|
||||||
|
result = await db.execute(
|
||||||
|
select(User)
|
||||||
|
.where(User.is_admin == True, User.pocketid_issuer.isnot(None))
|
||||||
|
.order_by(User.id)
|
||||||
|
.limit(1)
|
||||||
|
)
|
||||||
|
admin = result.scalar_one_or_none()
|
||||||
|
if admin is None:
|
||||||
|
result = await db.execute(
|
||||||
|
select(User).where(User.is_admin == True).order_by(User.id).limit(1)
|
||||||
|
)
|
||||||
|
admin = result.scalar_one_or_none()
|
||||||
|
return admin
|
||||||
|
|
||||||
|
|
||||||
async def _get_pocketid_config(db: AsyncSession):
|
async def _get_pocketid_config(db: AsyncSession):
|
||||||
"""Get PocketID config from DB (admin user) falling back to env vars."""
|
"""Get PocketID config from DB (admin user) falling back to env vars."""
|
||||||
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
|
admin = await _config_admin(db)
|
||||||
admin = result.scalar_one_or_none()
|
|
||||||
issuer = (admin and admin.pocketid_issuer) or settings.pocketid_issuer
|
issuer = (admin and admin.pocketid_issuer) or settings.pocketid_issuer
|
||||||
client_id = (admin and admin.pocketid_client_id) or settings.pocketid_client_id
|
client_id = (admin and admin.pocketid_client_id) or settings.pocketid_client_id
|
||||||
client_secret = (admin and admin.pocketid_client_secret) or settings.pocketid_client_secret
|
client_secret = (admin and admin.pocketid_client_secret) or settings.pocketid_client_secret
|
||||||
@@ -26,8 +48,7 @@ async def _get_pocketid_config(db: AsyncSession):
|
|||||||
|
|
||||||
async def _get_allowed_group(db: AsyncSession):
|
async def _get_allowed_group(db: AsyncSession):
|
||||||
"""Group a PocketID user must belong to in order to sign in (None = allow all)."""
|
"""Group a PocketID user must belong to in order to sign in (None = allow all)."""
|
||||||
result = await db.execute(select(User).where(User.is_admin == True).limit(1))
|
admin = await _config_admin(db)
|
||||||
admin = result.scalar_one_or_none()
|
|
||||||
group = (admin and admin.pocketid_allowed_group) or settings.pocketid_allowed_group
|
group = (admin and admin.pocketid_allowed_group) or settings.pocketid_allowed_group
|
||||||
return (group or "").strip() or None
|
return (group or "").strip() or None
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user