Files
fitguide/tests/test_ldap_login.py
T
2026-08-17 21:30:52 -03:00

150 lines
4.9 KiB
Python

import pytest
from app.core.config import settings
from app.crud import role as role_crud
from app.crud import user as user_crud
from app.services import ldap as ldap_service
@pytest.fixture
def ldap_enabled(monkeypatch):
monkeypatch.setattr(settings, "ldap_enabled", True)
def _fake_identity(username="jdoe", full_name="Jane Doe"):
return ldap_service.LdapIdentity(
username=username,
email=f"{username}@example.com",
full_name=full_name,
)
async def test_ldap_login_provisions_user_with_default_role(
client, seeded, db_sessionmaker, monkeypatch, ldap_enabled
):
# An admin has marked the "user" role as default.
async with db_sessionmaker() as db:
role = await role_crud.get(db, seeded["roles"]["user"].id)
await role_crud.set_default(db, role)
async def fake_authenticate(username, password):
assert (username, password) == ("jdoe", "secret")
return _fake_identity()
monkeypatch.setattr(ldap_service, "authenticate", fake_authenticate)
resp = await client.post(
"/api/auth/ldap-login",
data={"username": "jdoe", "password": "secret"},
)
assert resp.status_code == 200, resp.text
access = resp.json()["access_token"]
# A local profile was provisioned from the username with the default role.
async with db_sessionmaker() as db:
user = await user_crud.get_by_username(db, "jdoe")
assert user is not None
assert user.email == "jdoe@example.com"
assert user.full_name == "Jane Doe"
assert user.auth_source == "ldap"
assert user.hashed_password is None
assert {r.name for r in user.roles} == {"user"}
# The issued token authenticates.
me = await client.get(
"/api/users/me", headers={"Authorization": f"Bearer {access}"}
)
assert me.status_code == 200
assert me.json()["username"] == "jdoe"
async def test_ldap_login_is_idempotent(
client, seeded, db_sessionmaker, monkeypatch, ldap_enabled
):
async with db_sessionmaker() as db:
role = await role_crud.get(db, seeded["roles"]["user"].id)
await role_crud.set_default(db, role)
async def fake_authenticate(username, password):
return _fake_identity()
monkeypatch.setattr(ldap_service, "authenticate", fake_authenticate)
for _ in range(2):
resp = await client.post(
"/api/auth/ldap-login", data={"username": "jdoe", "password": "secret"}
)
assert resp.status_code == 200
async with db_sessionmaker() as db:
assert await user_crud.count(db) == 1
async def test_ldap_login_bad_credentials(client, seeded, monkeypatch, ldap_enabled):
async def fake_authenticate(username, password):
return None
monkeypatch.setattr(ldap_service, "authenticate", fake_authenticate)
resp = await client.post(
"/api/auth/ldap-login", data={"username": "jdoe", "password": "nope"}
)
assert resp.status_code == 401
@pytest.mark.skip(
"Not required, can cause issues if running against a live LDAP server"
)
async def test_ldap_login_disabled_returns_404(client, seeded):
# ldap_enabled defaults to False.
resp = await client.post(
"/api/auth/ldap-login", data={"username": "jdoe", "password": "secret"}
)
assert resp.status_code == 404
async def test_ldap_authenticate_short_circuits_when_disabled():
# No network call: disabled or empty credentials return None immediately.
assert await ldap_service.authenticate("jdoe", "secret") is None
async def test_set_default_role_is_exclusive(db_sessionmaker):
async with db_sessionmaker() as db:
a = await role_crud.create(db, name="alpha")
b = await role_crud.create(db, name="beta")
await role_crud.set_default(db, a)
assert (await role_crud.get_default(db)).id == a.id
# Marking another default clears the previous one.
await role_crud.set_default(db, b)
default = await role_crud.get_default(db)
assert default.id == b.id
await db.refresh(a)
assert a.is_default is False
async def test_local_login_rejects_ldap_user(
client, seeded, db_sessionmaker, monkeypatch, ldap_enabled
):
"""An LDAP-provisioned user (no local password) can't use the local login."""
async with db_sessionmaker() as db:
role = await role_crud.get(db, seeded["roles"]["user"].id)
await role_crud.set_default(db, role)
async def fake_authenticate(username, password):
return _fake_identity()
monkeypatch.setattr(ldap_service, "authenticate", fake_authenticate)
await client.post(
"/api/auth/ldap-login", data={"username": "jdoe", "password": "secret"}
)
# Local login with the synthesized email must fail (no local password).
resp = await client.post(
"/api/auth/login",
data={"username": "jdoe@example.com", "password": "secret"},
)
assert resp.status_code == 401