feat: trigger LDAP background sync on successful login

This commit is contained in:
Oliver Hofmann 2026-04-27 18:45:30 +02:00
parent 21574d3a57
commit 97ec689341
2 changed files with 40 additions and 1 deletions

View File

@ -1,4 +1,4 @@
from fastapi import APIRouter, Depends, Form, Request from fastapi import APIRouter, BackgroundTasks, Depends, Form, Request
from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@ -7,6 +7,7 @@ from app.core.auth import clear_auth_cookie, create_access_token, set_auth_cooki
from app.core.config import get_settings from app.core.config import get_settings
from app.core.database import get_db from app.core.database import get_db
from app.modules.auth.dependencies import get_current_user from app.modules.auth.dependencies import get_current_user
from app.modules.auth.ldap import sync_all_users
from app.modules.auth.schemas import UserOut from app.modules.auth.schemas import UserOut
from app.modules.auth.service import authenticate_user from app.modules.auth.service import authenticate_user
@ -27,6 +28,7 @@ async def login_page(request: Request):
@router.post("/login", response_class=HTMLResponse) @router.post("/login", response_class=HTMLResponse)
async def login( async def login(
request: Request, request: Request,
background_tasks: BackgroundTasks,
username: str = Form(...), username: str = Form(...),
password: str = Form(...), password: str = Form(...),
db: Session = Depends(get_db), db: Session = Depends(get_db),
@ -39,6 +41,17 @@ async def login(
{"nav_items": _NAV, "app_version": "0.1.0", "error": "Ungültige Zugangsdaten."}, {"nav_items": _NAV, "app_version": "0.1.0", "error": "Ungültige Zugangsdaten."},
status_code=200, status_code=200,
) )
if settings.LDAP_ENABLED:
background_tasks.add_task(
sync_all_users,
username,
password,
settings.LDAP_SERVER,
settings.LDAP_DOMAIN,
settings.LDAP_SEARCH_BASE,
settings.LDAP_SYNC_MIN_INTERVAL_HOURS,
settings.LDAP_SYNC_LETTER_DELAY_SECONDS,
)
token = create_access_token(username=user.username, is_admin=user.is_admin) token = create_access_token(username=user.username, is_admin=user.is_admin)
response = RedirectResponse(url="/", status_code=303) response = RedirectResponse(url="/", status_code=303)
set_auth_cookie(response, token) set_auth_cookie(response, token)

View File

@ -71,3 +71,29 @@ def test_logout_clears_cookie_and_redirects_to_landing(client, alice):
assert response.status_code in (302, 303, 307) assert response.status_code in (302, 303, 307)
assert response.headers["location"] == "/" assert response.headers["location"] == "/"
assert response.cookies.get("access_token", "") == "" assert response.cookies.get("access_token", "") == ""
from unittest.mock import patch as mock_patch
def test_ldap_login_sets_cookie_and_redirects(client, override_db):
"""LDAP login via mocked ldap_authenticate: cookie is set, redirects to /."""
ldap_attrs = {
"username": "ldapuser",
"full_name": "LDAP User",
"department": "EFI",
"role": "ST",
"account_expires": None,
}
with mock_patch("app.modules.auth.ldap.ldap_authenticate", return_value=ldap_attrs), \
mock_patch("app.modules.auth.ldap.sync_all_users"), \
mock_patch("app.modules.auth.router.settings") as mock_settings:
mock_settings.LDAP_ENABLED = True
mock_settings.LDAP_SERVER = "test"
mock_settings.LDAP_DOMAIN = "ADS1"
mock_settings.LDAP_SEARCH_BASE = "OU=test"
mock_settings.LDAP_SYNC_MIN_INTERVAL_HOURS = 12
mock_settings.LDAP_SYNC_LETTER_DELAY_SECONDS = 0.0
response = client.post("/auth/login", data={"username": "ldapuser", "password": "any"})
assert response.status_code in (302, 303, 307)
assert "access_token" in response.cookies