Files
A-Team-Security-Infra-Agent…/backend/auth/jwt_auth.py
nogueiraguh 1135e9d6a9 refactor: decompose monolith — app.py 10,600→143 lines, 30+ modules
Fase 0 complete: extract all business logic, auth, database, and 176
endpoints from monolithic app.py into dedicated modules.

Structure:
- app.py: FastAPI hub (CORS, routers, startup/shutdown)
- models.py: 13 Pydantic request models
- utils.py: shared utilities (embed status, upload validation, process registries)
- config.py: constants, env vars, model catalogs
- auth/: crypto, jwt_auth, oidc, rate_limit
- database/: db(), init_db(), schema DDL
- services/: genai, compliance, chat, terraform, embeddings, cis_reports, mcp
- routes/: 13 APIRouter modules (auth, users, oci_config, oci_explorer,
  genai, mcp, adb, embeddings, reports, chat, terraform, settings, cis_engine)

Also: README updated with OCIR auth instructions for manual docker run.

86 tests passing.
2026-04-06 15:20:10 -03:00

106 lines
4.0 KiB
Python

"""JWT authentication — current_user dependency, require roles, audit/log helpers."""
import uuid
import jwt as pyjwt
from fastapi import HTTPException, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from config import APP_SECRET, JWT_ALG
from database import db
security = HTTPBearer()
async def current_user(cred: HTTPAuthorizationCredentials = Depends(security)):
try:
p = pyjwt.decode(cred.credentials, APP_SECRET, algorithms=[JWT_ALG])
except pyjwt.ExpiredSignatureError:
raise HTTPException(401, "Token expirado")
except pyjwt.InvalidTokenError:
raise HTTPException(401, "Token inválido")
with db() as c:
u = c.execute("SELECT * FROM users WHERE id=? AND is_active=1", (p["sub"],)).fetchone()
s = c.execute("SELECT * FROM sessions WHERE id=? AND is_active=1", (p["sid"],)).fetchone()
if not u or not s:
raise HTTPException(401, "Sessão inválida")
return dict(u)
def _user_from_token(token: str):
try:
p = pyjwt.decode(token, APP_SECRET, algorithms=[JWT_ALG])
except Exception:
raise HTTPException(401, "Token inválido")
with db() as c:
u = c.execute("SELECT * FROM users WHERE id=? AND is_active=1", (p["sub"],)).fetchone()
s = c.execute("SELECT * FROM sessions WHERE id=? AND is_active=1", (p["sid"],)).fetchone()
if not u or not s:
raise HTTPException(401, "Sessão inválida")
return dict(u)
def require(*roles):
async def dep(u=Depends(current_user)):
if u["role"] not in roles:
raise HTTPException(403, f"Requer role: {', '.join(roles)}")
return u
return dep
def _audit(uid, uname, action, resource=None, details=None, ip=None):
with db() as c:
c.execute(
"INSERT INTO audit_log (id,user_id,username,action,resource,details,ip) VALUES (?,?,?,?,?,?,?)",
(str(uuid.uuid4()), uid, uname, action, resource, details, ip))
def _config_log(config_type, config_id, config_name, severity, action, message, uid=None, uname=None):
with db() as c:
c.execute(
"INSERT INTO config_logs (id,config_type,config_id,config_name,severity,action,message,user_id,username) VALUES (?,?,?,?,?,?,?,?,?)",
(str(uuid.uuid4()), config_type, config_id, config_name or "", severity, action, str(message)[:2000], uid, uname))
def _chat_log(sid, mid, uid, severity, source, action, message):
with db() as c:
c.execute(
"INSERT INTO chat_logs (id,session_id,message_id,user_id,severity,source,action,message) VALUES (?,?,?,?,?,?,?,?)",
(str(uuid.uuid4()), sid, mid, uid, severity, source, action, str(message)[:2000]))
# ── Access Control ───────────────────────────────────────────────────────────
_CONFIG_TABLES = {
"oci": "oci_configs",
"genai": "genai_configs",
"adb": "adb_vector_configs",
"mcp": "mcp_servers",
}
def _verify_config_access(config_type: str, config_id: str, user: dict, *, require_owner: bool = False) -> dict:
table = _CONFIG_TABLES.get(config_type)
if not table:
raise HTTPException(400, f"Tipo de config inválido: {config_type}")
with db() as c:
row = c.execute(f"SELECT * FROM {table} WHERE id=?", (config_id,)).fetchone()
if not row:
raise HTTPException(404)
row = dict(row)
if user["role"] == "admin":
return row
is_owner = row.get("user_id") == user["id"]
is_global = row.get("is_global", 0)
if not is_owner and not is_global:
raise HTTPException(404)
if require_owner and not is_owner:
raise HTTPException(403, "Apenas o dono pode modificar este recurso")
return row
def _verify_report_access(report_id: str, user: dict) -> dict:
with db() as c:
row = c.execute("SELECT * FROM reports WHERE id=? AND user_id=?", (report_id, user["id"])).fetchone()
if not row:
raise HTTPException(404)
return dict(row)