Add 'gerenciador/' from commit '34cc9c75a57dedbf61a6e6a1ba1f35f76e72434b'
git-subtree-dir: gerenciador git-subtree-mainline:f4f546c928git-subtree-split:34cc9c75a5
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
"""
|
||||
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'<!doctype html><meta charset="utf-8"><title>GTI Fiscal</title>'
|
||||
f'<p style="font-family:system-ui;padding:24px">{mensagem} <a href="/">Voltar ao painel</a></p>',
|
||||
status_code=status_code,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/sso/fiscal")
|
||||
def iniciar_sso_fiscal(request: Request, next: str | None = None, state: 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)
|
||||
|
||||
# Sem state o fluxo não começou no Fiscal (ex.: clique na sidebar): manda
|
||||
# para o login do Fiscal, que cria o state e devolve para cá.
|
||||
if not sso.estado_valido(state):
|
||||
return RedirectResponse(sso.url_login_fiscal(destino), status_code=303)
|
||||
|
||||
parametros = urlencode({"state": state, "next": destino})
|
||||
if request.url.scheme != "https":
|
||||
publica = os.environ.get("SSO_GERENCIADOR_URL_PUBLICA", "").rstrip("/")
|
||||
if publica.startswith("https://"):
|
||||
return RedirectResponse(f"{publica}/sso/fiscal?{parametros}", 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:
|
||||
return RedirectResponse(f"/login?{urlencode({'next': f'/sso/fiscal?{parametros}'})}", 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, nonce=state)
|
||||
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
|
||||
Reference in New Issue
Block a user