feat: SSO from GTI Gerenciador and the Gerenciador visual identity

Collaborators logged into GTI Gerenciador open GTI Fiscal without a
second password. The panel signs a 60 s JWT (Ed25519; the Hub holds only
the public key); the Hub checks signature, iss/aud/exp/nbf, maximum
lifetime, nonce against a one-time state cookie set when the flow starts
at GET /login (login-CSRF protection) and a single-use jti
(sso_used_assertions). Collaborators are provisioned in admin_users with
auth_source=GTI_GERENCIADOR and no password; a CHECK constraint makes a
passwordless local account or a federated account with a password
impossible (migration 0021). Sessions last FEDERATED_SESSION_SECONDS
(1 h) and are renewed silently through the panel.

The local admin stays as break-glass at /login/local, audited. Logout ends
only the Hub session. Every SSO success/rejection (stable reason code),
logout and local login is audited with the real client IP, never the
token. verify_password now fails closed on a missing hash instead of
raising.

Visual identity: gti-theme.css is a verbatim copy of the panel's
design system (tokens, sidebar, light/dark theme) plus its tema.js,
sidebar.js and logo; control-panel.css keeps only Hub components, all
colours from the panel tokens. Page structure and features unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
gti
2026-09-23 12:21:26 -03:00
co-authored by Claude Opus 5.5
parent 91a2dda969
commit 64d3fc56e2
21 changed files with 1290 additions and 122 deletions
+7
View File
@@ -17,6 +17,13 @@ FORWARDED_ALLOW_IPS=127.0.0.1
# 1 once HTTPS terminates in front of the Hub (session/CSRF cookies become Secure).
WEB_COOKIE_SECURE=0
# SSO from GTI Gerenciador (docs/PILOT_DEPLOYMENT.md, "Human access"). Needs HTTPS (WEB_COOKIE_SECURE=1).
# PUBLIC key only (raw Ed25519, base64url) — the private key lives only in the panel.
SSO_GERENCIADOR_CHAVE_PUBLICA=
SSO_START_URL=https://gtigerenciador.example.gti/sso/fiscal
# Collaborator session lifetime; afterwards they are signed in again transparently.
FEDERATED_SESSION_SECONDS=3600
LOG_LEVEL=INFO
AGENT_ONLINE_THRESHOLD_SECONDS=120
+5
View File
@@ -52,6 +52,11 @@ services:
FORWARDED_ALLOW_IPS: ${FORWARDED_ALLOW_IPS:-127.0.0.1}
# 1 = session/CSRF cookies are sent only over HTTPS. Set once TLS is in front.
WEB_COOKIE_SECURE: ${WEB_COOKIE_SECURE:-0}
# SSO from GTI Gerenciador (central/app/sso.py): the panel's Ed25519 PUBLIC key
# and its /sso/fiscal URL. Both empty = SSO off (local login only).
SSO_GERENCIADOR_CHAVE_PUBLICA: ${SSO_GERENCIADOR_CHAVE_PUBLICA:-}
SSO_START_URL: ${SSO_START_URL:-}
FEDERATED_SESSION_SECONDS: ${FEDERATED_SESSION_SECONDS:-3600}
# AGENT_DEV_TOKEN is intentionally NOT set: real Agents are registered with central/scripts/register_agent.py.
ports:
- "${HUB_BIND:-127.0.0.1}:${HUB_PORT:-8000}:8000"