Move auth session signing into auth_service.login

This commit is contained in:
2026-04-17 15:33:09 +02:00
parent 33643880ed
commit 58112fb191
4 changed files with 119 additions and 71 deletions

View File

@@ -20,7 +20,6 @@ from app.dependencies import (
SettingsDep,
)
from app.models.auth import LoginRequest, LoginResponse, LogoutResponse
from app.services.auth_service import sign_session_token
from app.utils.constants import SESSION_COOKIE_NAME
log: structlog.stdlib.BoundLogger = structlog.get_logger()
@@ -59,10 +58,11 @@ async def login(
HTTPException: 401 if the password is incorrect.
"""
try:
session = await auth_service.login(
signed_token, expires_at = await auth_service.login(
db,
password=body.password,
session_duration_minutes=settings.session_duration_minutes,
session_secret=settings.session_secret,
session_repo=session_repo,
)
except ValueError as exc:
@@ -71,10 +71,6 @@ async def login(
detail=str(exc),
) from exc
signed_token = sign_session_token(
session.token,
settings.session_secret,
)
response.set_cookie(
key=SESSION_COOKIE_NAME,
value=signed_token,
@@ -83,7 +79,7 @@ async def login(
secure=settings.session_cookie_secure,
max_age=settings.session_duration_minutes * 60,
)
return LoginResponse(token=signed_token, expires_at=session.expires_at)
return LoginResponse(token=signed_token, expires_at=expires_at)
@router.post(

View File

@@ -79,17 +79,19 @@ async def login(
db: aiosqlite.Connection,
password: str,
session_duration_minutes: int,
session_secret: str,
session_repo: SessionRepository = default_session_repo,
) -> Session:
"""Verify *password* and create a new session on success.
) -> tuple[str, str]:
"""Verify *password*, create a new session, and sign the token.
Args:
db: Active aiosqlite connection.
password: Plain-text password supplied by the user.
session_duration_minutes: How long the new session is valid for.
session_secret: Secret used to sign the session token.
Returns:
A :class:`~app.models.auth.Session` domain model for the new session.
A tuple of the signed session token and its expiry timestamp.
Raises:
ValueError: If the password is incorrect or no password hash is stored.
@@ -111,8 +113,9 @@ async def login(
session = await session_repo.create_session(
db, token=token, created_at=created_iso, expires_at=expires_iso
)
log.info("bangui_login_success", token_prefix=token[:8])
return session
signed_token = sign_session_token(session.token, session_secret)
log.info("bangui_login_success", token_prefix=session.token[:8])
return signed_token, session.expires_at
async def validate_session(

View File

@@ -6,41 +6,42 @@ layers depend on, without binding them to concrete module implementations.
from __future__ import annotations
from collections.abc import Awaitable, Callable
from typing import Protocol, runtime_checkable
from typing import TYPE_CHECKING, Protocol, runtime_checkable
import aiosqlite
import aiohttp
if TYPE_CHECKING:
from collections.abc import Awaitable, Callable
from app.models.auth import Session
from app.models.ban import BanOrigin, JailBannedIpsResponse, TimeRange
from app.models.blocklist import (
BlocklistSource,
ImportLogListResponse,
ImportRunResult,
ImportSourceResult,
PreviewResponse,
ScheduleConfig,
ScheduleInfo,
)
from app.models.config import (
AddLogPathRequest,
GlobalConfigResponse,
GlobalConfigUpdate,
JailConfigListResponse,
JailConfigResponse,
JailConfigUpdate,
LogPreviewRequest,
LogPreviewResponse,
MapColorThresholdsResponse,
MapColorThresholdsUpdate,
RegexTestResponse,
Fail2BanLogResponse,
ServiceStatusResponse,
)
from app.models.geo import GeoBatchLookup, GeoEnricher, GeoInfo
from app.models.history import HistoryListResponse, IpDetailResponse
from app.models.server import ServerSettingsResponse, ServerSettingsUpdate, ServerStatus
import aiohttp
import aiosqlite
from app.models.auth import Session
from app.models.ban import BanOrigin, JailBannedIpsResponse, TimeRange
from app.models.blocklist import (
BlocklistSource,
ImportLogListResponse,
ImportRunResult,
ImportSourceResult,
PreviewResponse,
ScheduleConfig,
ScheduleInfo,
)
from app.models.config import (
AddLogPathRequest,
GlobalConfigResponse,
GlobalConfigUpdate,
JailConfigListResponse,
JailConfigResponse,
JailConfigUpdate,
LogPreviewRequest,
LogPreviewResponse,
MapColorThresholdsResponse,
MapColorThresholdsUpdate,
RegexTestResponse,
)
from app.models.geo import GeoBatchLookup, GeoEnricher, GeoInfo
from app.models.history import HistoryListResponse, IpDetailResponse
from app.models.jail import JailDetailResponse, JailListResponse
from app.models.server import ServerSettingsResponse, ServerSettingsUpdate, ServerStatus
class AuthService(Protocol):
@@ -51,8 +52,9 @@ class AuthService(Protocol):
db: aiosqlite.Connection,
password: str,
session_duration_minutes: int,
session_secret: str,
session_repo: object | None = None,
) -> Session:
) -> tuple[str, str]:
...
async def validate_session(