""" GET /sso/fiscal — ponto de entrada do item "Fiscal" da sidebar. Com o funcionário logado e ativo, emite a asserção (app/sso.py) e a entrega ao callback do Fiscal num POST auto-submetido; sem sessão, manda para o login normal e volta para cá depois. Só roda por HTTPS (acesso pelo domínio público, atrás do NPM): por HTTP redireciona para SSO_GERENCIADOR_URL_PUBLICA. A conta de bootstrap do .env não tem linha em FUNCIONARIO_PAINEL, portanto nenhum ID estável para virar identidade no Fiscal — é recusada (o Fiscal tem o próprio admin de emergência). """ import os from urllib.parse import urlencode from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse, RedirectResponse from fastapi.templating import Jinja2Templates from .. import sso from ..auth import NaoAutenticado, exigir_login from ..db import funcionarios as db_funcionarios from ..db import log as db_log router = APIRouter() templates = Jinja2Templates(directory="app/templates") def _pagina_erro(mensagem: str, status_code: int) -> HTMLResponse: return HTMLResponse( f'GTI Fiscal' f'

{mensagem} Voltar ao painel

', status_code=status_code, ) @router.get("/sso/fiscal") def iniciar_sso_fiscal(request: Request, next: str | None = None): destino = sso.proximo_seguro(next) if not sso.configurado(): return _pagina_erro("O acesso ao GTI Fiscal não está configurado neste painel.", 503) if request.url.scheme != "https": publica = os.environ.get("SSO_GERENCIADOR_URL_PUBLICA", "").rstrip("/") if publica.startswith("https://"): return RedirectResponse(f"{publica}/sso/fiscal?{urlencode({'next': destino})}", status_code=303) return _pagina_erro("O acesso ao GTI Fiscal só funciona pelo endereço HTTPS do painel.", 400) try: usuario = exigir_login(request) except NaoAutenticado: volta = f"/sso/fiscal?{urlencode({'next': destino})}" return RedirectResponse(f"/login?{urlencode({'next': volta})}", status_code=303) funcionario = db_funcionarios.obter_por_login(usuario.login) if funcionario is None: db_log.registrar(str(usuario), "sso_fiscal", "funcionario", usuario.login, False, "conta de bootstrap não usa SSO") return _pagina_erro("A conta de bootstrap não acessa o GTI Fiscal — entre com seu usuário de funcionário.", 403) assercao = sso.emitir_assercao(funcionario) db_log.registrar(str(usuario), "sso_fiscal", "funcionario", str(funcionario["ID"]), True) resposta = templates.TemplateResponse( request, "sso_fiscal.html", {"acao": sso.url_callback(), "assercao": assercao, "proximo": destino} ) # A CSP padrão (main.py) só permite form-action 'self'; esta página precisa # postar exatamente para a origem do Fiscal e para nenhum outro lugar. resposta.headers["Content-Security-Policy"] = ( "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; " f"form-action {sso.origem_callback()}; frame-ancestors 'none'; base-uri 'none'" ) resposta.headers["Cache-Control"] = "no-store" resposta.headers["Referrer-Policy"] = "no-referrer" return resposta