obsidian-vault/ligbox-ops-platform/specs/003-desk-auth-rbac/spec.md
2026-06-19 17:26:42 +00:00

10 KiB

Feature Specification: Desk Auth & RBAC (003)

Feature Branch: 003-desk-auth-rbac

Created: 2026-06-10

Status: Draft → Ready for plan

Input: Proteger o Ligbox Ops Desk (API pública em api.ops.ligbox.com.br) com login de utilizadores e controlo de acesso por perfil (RBAC). Utilizadores iniciais mapeados aos accounts Linux da VM122: root, admin, mini, mais noc para monitorização.

Backlog: OPS-4 (auth), OPS-6 (RBAC), DESK-1/2 (Desk protegido)


User Scenarios & Testing (mandatory)

User Story 1 — Login no Support Desk (Priority: P1)

Como membro da equipa Ligbox, quero autenticar-me no Desk com utilizador e senha para aceder a tickets e dashboards sem que dados de clientes fiquem expostos na internet.

Why this priority: Hoje qualquer pessoa com o URL lê tickets, CNPJs e perfis de empresa. É o maior risco de segurança e privacidade da plataforma.

Independent Test: Abrir https://desk.ligbox.com.br sem sessão → ver ecrã de login. Após credenciais válidas → dashboard carrega. curl sem token em /api/v1/desk/tickets → HTTP 401.

Acceptance Scenarios:

  1. Given utilizador não autenticado, When abre o Desk UI, Then vê formulário de login (não o dashboard).
  2. Given credenciais válidas (root / senha correcta), When submete login, Then recebe token de sessão e acede ao dashboard.
  3. Given credenciais inválidas, When submete login, Then recebe erro genérico sem revelar se o utilizador existe.
  4. Given token expirado, When UI chama API protegida, Then redirecciona para login.
  5. Given pedido API sem Authorization nem webhook secret, When acede endpoint humano (/api/v1/desk/*), Then HTTP 401.

User Story 2 — Perfis e permissões (Priority: P1)

Como administrador, quero que cada técnico veja e faça apenas o que o seu perfil permite — Roger com controlo total, chefe de ops com gestão operacional, suporte com tickets, NOC só leitura.

Why this priority: Autenticação sem autorização não resolve o problema; roles definem o modelo operacional da equipa.

Independent Test: Login como mini (technician) → pode ver tickets e fechar os atribuídos. Login como noc → vê dashboard e alertas Wazuh mas botão "Fechar ticket" ausente e PATCH retorna 403.

Acceptance Scenarios:

  1. Given root (super_admin), When acede qualquer endpoint humano, Then permitido (incluindo gestão de utilizadores).
  2. Given admin (ops_lead), When tenta criar utilizador, Then HTTP 403; When fecha ticket ou dispara audit, Then permitido.
  3. Given mini (technician), When consulta tickets, Then vê lista completa; When altera ticket não atribuído a si, Then HTTP 403 (excepto tickets sem assignee — pode assumir).
  4. Given noc, When consulta dashboard/health/Wazuh, Then permitido em leitura; When tenta PATCH ticket ou POST audit, Then HTTP 403.
  5. Given noc, When vê ticket com company_profile, Then campos sensíveis (CNPJ, morada, emails billing) mascarados na resposta API e UI.

User Story 3 — Webhooks e integrações intactos (Priority: P1)

Como sistema integrado (VM112, Wazuh), continuo a enviar eventos via secret sem passar pelo login humano — a auth RBAC não pode quebrar o funil de onboarding.

Why this priority: A plataforma já recebe eventos de produção; regressão aqui bloqueia novos clientes.

Independent Test: POST /api/v1/webhooks/onboard com X-Webhook-Secret válido sem JWT → HTTP 200. Com secret inválido → 401.

Acceptance Scenarios:

  1. Given header X-Webhook-Secret válido, When POST webhook onboard ou wazuh, Then processado sem JWT.
  2. Given JWT válido mas sem secret, When POST webhook, Then HTTP 401 (webhooks não aceitam JWT como substituto).
  3. Given GET /health, When sem auth, Then HTTP 200 (healthcheck Traefik/monitoring).

User Story 4 — Gestão de utilizadores (Priority: P2)

Como super_admin (Roger), quero listar utilizadores do Desk, activar/desactivar contas e alterar roles sem SSH na VM.

Why this priority: Operação diária; não bloqueia MVP se seeds iniciais bastarem no lançamento.

Independent Test: Login rootGET /api/v1/auth/users lista 4 users. PATCH role de mini → technician mantido; tentativa por admin → 403.

Acceptance Scenarios:

  1. Given super_admin autenticado, When lista utilizadores, Then vê username, role, activo, último login (sem password hash).
  2. Given super_admin, When desactiva utilizador noc, Then login desse user falha no próximo pedido.
  3. Given ops_lead ou inferior, When acede /api/v1/auth/users, Then HTTP 403.

Utilizadores iniciais (seed VM122)

Username Role Perfil operacional Senha inicial
root super_admin Roger / dono — tudo: users, tenants, audit, tickets, config 805353 (bootstrap; rotacionar em produção)
admin ops_lead Chefe de operações — tickets, audit, fechar casos, funil completo 805353
mini technician Suporte N1/N2 — tickets atribuídos, timeline, acções limitadas 805353
noc noc Monitorização — só leitura: dashboard, Wazuh, health 805353

Nota: Accounts Linux (root, admin, mini) já existem na VM122 com sudo. O utilizador noc é criado no seed do Desk (conta só na app, não requer user OS). Passwords Desk são independentes do OS após seed — alteração no Desk não muda SSH.


Matriz de permissões (RBAC)

Legenda: permitido · 🔒 leitura restrita (dados mascarados) · negado

Recurso / Acção super_admin ops_lead technician noc
Login / logout
GET /health público
Webhooks (POST /webhooks/*) secret secret secret secret
Dashboard summary 🔒
Listar tickets 🔒
Ver detalhe ticket 🔒
Fechar / reabrir ticket *
Atribuir ticket (assigned_to) **
Funil onboarding (completo) parcial 🔒 resumo
Timeline sessão 🔒
Audit overview / scorecard 🔒
Disparar audit manual
Listar tenants 🔒
Eventos webhook (todos) onboard+wazuh wazuh only
Infra status (VM112, Wazuh)
Gestão utilizadores
Ver company_profile completo mascarado
Ver billing_state

* technician: PATCH apenas se assigned_to = self OU assigned_to IS NULL (pode assumir ao fechar).

** technician: pode atribuir a si próprio; ops_lead+ pode atribuir a qualquer user.


Functional Requirements

  • FR-001: Sistema MUST exigir autenticação (JWT Bearer) em todos os endpoints humanos sob /api/v1/ excepto /health, /api/health, e webhooks.
  • FR-002: Sistema MUST validar role em cada endpoint conforme matriz RBAC.
  • FR-003: Sistema MUST armazenar passwords com hash bcrypt (cost ≥ 12); nunca plaintext.
  • FR-004: Sistema MUST emitir JWT com claims: sub (username), role, exp (TTL configurável, default 8h).
  • FR-005: Sistema MUST manter canal paralelo de auth para webhooks via X-Webhook-Secret (inalterado).
  • FR-006: UI MUST apresentar login antes de qualquer vista; MUST enviar Authorization: Bearer <token> em pedidos API.
  • FR-007: UI MUST ocultar acções não permitidas ao role (ex.: noc sem botão fechar ticket).
  • FR-008: Sistema MUST mascarar campos sensíveis em respostas para role noc (tax_id, morada, emails billing).
  • FR-009: Sistema MUST seed 4 utilizadores na primeira execução se tabela desk_users vazia.
  • FR-010: super_admin MUST poder listar, activar/desactivar users e alterar roles (P2).
  • FR-011: Sistema MUST adicionar assigned_to (nullable) em tickets para controlo technician (P2 mínimo: campo + PATCH por ops_lead).
  • FR-012: Sistema MUST registar last_login_at por utilizador.
  • FR-013: Sistema MUST falhar de forma segura: 401 sem token, 403 com token mas sem permissão.

Success Criteria

  • SC-001: 100% dos endpoints humanos devolvem 401 sem autenticação (verificado por script verify-auth.sh).
  • SC-002: Nenhum dado de ticket acessível publicamente em api.ops.ligbox.com.br após deploy.
  • SC-003: Webhooks VM112 e Wazuh continuam a funcionar sem alteração de secret.
  • SC-004: Cada um dos 4 roles passa testes de permissão documentados em quickstart.
  • SC-005: Tempo de login < 2s p95 na LAN.

Edge Cases

  • Token expirado durante sessão activa → UI pede re-login; não perde navegação abrupta sem mensagem.
  • Utilizador desactivado com token válido → próximo pedido API retorna 401.
  • Traefik healthcheck usa /health → permanece público.
  • Worker interno chama API (audit cycle) → usa OPS_INTERNAL_TOKEN ou chama localhost sem auth (decisão no plan).
  • Brute force login → rate limit 5 tentativas/min por IP (Redis ou in-memory MVP).
  • CORS: frontend e API no mesmo origin via Traefik (desk.ligbox.com.br/api proxy) — validar no deploy.

Assumptions

  • VM122 Debian 12, API FastAPI existente, SQLite ops.db.
  • Frontend estático servido por nginx; sem framework JS pesado.
  • Traefik CT114 termina TLS e expõe desk.ligbox.com.br e api.ops.ligbox.com.br.
  • Senha bootstrap 805353 será rotacionada após primeiro login super_admin (processo manual documentado).
  • Assignment de tickets (FR-011) pode entrar na mesma entrega se simples; caso contrário fase 2 da 003.

Out of Scope

  • SSO / OAuth externo (Google, Azure AD)
  • MFA / TOTP no Desk (portal onboard já tem; Desk fica para spec futura)
  • Permissões por tenant (todos os roles Ligbox vêem todos os tenants no MVP)
  • Audit log de acções de utilizador (spec futura compliance)
  • Sincronização automática password Desk ↔ Linux PAM

Dependencies

  • Features 001 (webhooks) e 002 (Wazuh) — deployadas e funcionais.
  • python-jose ou PyJWT + passlib[bcrypt] no requirements API.
  • Redis existente (rate limit opcional).