Files
GTI_GERENCIADOR_FISCAL/tests/test_auth.py
T
GustavoandClaude Sonnet 5 e5f5d4211c fix: desativar/rebaixar funcionario nao revogava sessao ativa (ate 12h)
Perfil e status ativo vinham so do cookie assinado (session.py), entao um
funcionario desativado (ATIVO=0) ou rebaixado (ADMIN->PADRAO) continuava
com acesso total ate o cookie expirar (ate 12h) - inclusive a
/funcionarios se era admin.

exigir_login (app/auth.py) agora reconfirma contra o banco a cada
requisicao quando o login nao e o da conta de bootstrap (ADMIN_USER do
.env, que nao tem linha em FUNCIONARIO_PAINEL e continua sempre admin via
variavel de ambiente): busca db_funcionarios.obter_por_login(login); se
nao existir mais ou ATIVO != 1, levanta NaoAutenticado (forca novo
login); caso contrario, monta o UsuarioLogado com o PERFIL atual do
banco, nao o do cookie - rebaixamento tambem passa a ter efeito imediato.

Testes de regressao em tests/test_auth.py:
- test_exigir_login_autentica_funcionario_ativo
- test_exigir_login_revoga_sessao_ao_desativar_funcionario
- test_exigir_admin_usa_perfil_atual_do_banco_nao_do_cookie
- test_exigir_login_conta_bootstrap_nao_consulta_banco

Ajustou tambem test_exigir_admin_rejeita_padrao (usava um login fake sem
linha em FUNCIONARIO_PAINEL, que agora conflita com a checagem nova -
passou a usar a fixture funcionario_teste). Suite inteira roda
147 passed apos a mudanca.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13 21:18:58 -03:00

165 lines
6.0 KiB
Python

import pytest
from fastapi import Depends, FastAPI, HTTPException
from fastapi.testclient import TestClient
from app import session
from app.auth import NaoAutenticado, UsuarioLogado, autenticar_credenciais, exigir_admin, exigir_login
from app.db import funcionarios as db_funcionarios
from app.db.connection import get_connection
app_teste = FastAPI()
@app_teste.get("/protegido")
def rota_protegida(usuario: UsuarioLogado = Depends(exigir_login)):
return {"usuario": str(usuario), "perfil": usuario.perfil}
@app_teste.get("/so-admin")
def rota_admin(usuario: UsuarioLogado = Depends(exigir_admin)):
return {"usuario": str(usuario)}
@app_teste.exception_handler(NaoAutenticado)
def _handler_nao_autenticado(request, exc):
raise HTTPException(status_code=401, detail="não autenticado")
client = TestClient(app_teste, follow_redirects=False)
def _cookie_sessao(login: str, nome: str, perfil: str) -> dict:
return {session.SESSION_COOKIE_NAME: session.criar_token(login, nome, perfil)}
def test_sem_cookie_retorna_401():
resposta = client.get("/protegido")
assert resposta.status_code == 401
def test_cookie_invalido_retorna_401():
resposta = client.get("/protegido", cookies={session.SESSION_COOKIE_NAME: "lixo"})
assert resposta.status_code == 401
def test_cookie_valido_retorna_dados_do_usuario():
resposta = client.get("/protegido", cookies=_cookie_sessao("admin", "Admin", "ADMIN"))
assert resposta.status_code == 200
assert resposta.json() == {"usuario": "Admin", "perfil": "ADMIN"}
def test_usuario_logado_str_retorna_nome():
usuario = UsuarioLogado(login="fulano", nome="Fulano da Silva", perfil="PADRAO")
assert str(usuario) == "Fulano da Silva"
def test_usuario_logado_eh_admin():
assert UsuarioLogado(login="a", nome="A", perfil="ADMIN").eh_admin is True
assert UsuarioLogado(login="a", nome="A", perfil="PADRAO").eh_admin is False
def test_exigir_admin_aceita_admin():
resposta = client.get("/so-admin", cookies=_cookie_sessao("admin", "Admin", "ADMIN"))
assert resposta.status_code == 200
def test_exigir_admin_rejeita_padrao(funcionario_teste):
# exigir_login agora reconfirma o perfil contra o banco, então o login
# precisa existir de fato em FUNCIONARIO_PAINEL (funcionario_teste é
# cadastrado com PERFIL="PADRAO" — ver fixture abaixo).
resposta = client.get("/so-admin", cookies=_cookie_sessao(funcionario_teste, "Fulano", "PADRAO"))
assert resposta.status_code == 403
def test_autenticar_credenciais_admin_env():
# ADMIN_USER/ADMIN_PASSWORD vêm de tests/conftest.py ("admin"/"teste123")
usuario = autenticar_credenciais("admin", "teste123")
assert usuario is not None
assert usuario.perfil == "ADMIN"
assert usuario.login == "admin"
def test_autenticar_credenciais_admin_env_senha_errada():
assert autenticar_credenciais("admin", "senha_errada") is None
def test_autenticar_credenciais_admin_env_vazio_nao_autentica_vazio(monkeypatch):
monkeypatch.setenv("ADMIN_USER", "")
monkeypatch.setenv("ADMIN_PASSWORD", "")
assert autenticar_credenciais("", "") is None
def _limpar_login(login: str) -> None:
conn = get_connection()
try:
with conn.cursor() as cur:
cur.execute("DELETE FROM FUNCIONARIO_PAINEL WHERE LOGIN = %s", (login,))
finally:
conn.close()
@pytest.fixture
def funcionario_teste():
login = "teste.login.auth"
_limpar_login(login)
funcionario_id = db_funcionarios.criar_funcionario("Fulano de Teste", login, "senhaForte123", "PADRAO")
yield login
_limpar_login(login)
def test_autenticar_credenciais_funcionario_ativo(funcionario_teste):
usuario = autenticar_credenciais(funcionario_teste, "senhaForte123")
assert usuario is not None
assert usuario.nome == "Fulano de Teste"
assert usuario.perfil == "PADRAO"
def test_autenticar_credenciais_funcionario_senha_errada(funcionario_teste):
assert autenticar_credenciais(funcionario_teste, "senhaErrada") is None
def test_autenticar_credenciais_funcionario_inativo(funcionario_teste):
funcionario = db_funcionarios.obter_por_login(funcionario_teste)
db_funcionarios.alternar_ativo(funcionario["ID"]) # desativa
assert autenticar_credenciais(funcionario_teste, "senhaForte123") is None
def test_autenticar_credenciais_login_inexistente():
assert autenticar_credenciais("nao-existe-esse-login", "qualquer") is None
def test_exigir_login_autentica_funcionario_ativo(funcionario_teste):
resposta = client.get("/protegido", cookies=_cookie_sessao(funcionario_teste, "Fulano de Teste", "PADRAO"))
assert resposta.status_code == 200
assert resposta.json() == {"usuario": "Fulano de Teste", "perfil": "PADRAO"}
def test_exigir_login_revoga_sessao_ao_desativar_funcionario(funcionario_teste):
# Cookie "válido" (assinatura e validade OK) gerado antes de desativar.
cookies = _cookie_sessao(funcionario_teste, "Fulano de Teste", "PADRAO")
assert client.get("/protegido", cookies=cookies).status_code == 200
funcionario = db_funcionarios.obter_por_login(funcionario_teste)
db_funcionarios.alternar_ativo(funcionario["ID"]) # desativa
resposta = client.get("/protegido", cookies=cookies)
assert resposta.status_code == 401
def test_exigir_admin_usa_perfil_atual_do_banco_nao_do_cookie(funcionario_teste):
# Cookie diz ADMIN, mas o funcionário no banco é PADRAO (ex: foi
# rebaixado depois de logar) — exigir_admin precisa rejeitar.
cookies = _cookie_sessao(funcionario_teste, "Fulano de Teste", "ADMIN")
resposta = client.get("/so-admin", cookies=cookies)
assert resposta.status_code == 403
def test_exigir_login_conta_bootstrap_nao_consulta_banco(monkeypatch):
def _falha_se_chamado(login):
raise AssertionError("exigir_login não deveria consultar o banco para a conta de bootstrap")
monkeypatch.setattr(db_funcionarios, "obter_por_login", _falha_se_chamado)
resposta = client.get("/protegido", cookies=_cookie_sessao("admin", "Admin", "ADMIN"))
assert resposta.status_code == 200
assert resposta.json() == {"usuario": "Admin", "perfil": "ADMIN"}