# [DEF:ADR-0005:ADR]
# @STATUS ACTIVE
# @PURPOSE Define the authentication and authorization architecture for ss-tools: local auth, optional ADFS SSO federation, RBAC model, session management, and the security boundary between ss-tools (DevOps privileges) and Superset (BI privileges).
# @RELATION DEPENDS_ON -> [ADR-0001:ADR]
# @RELATION DEPENDS_ON -> [ADR-0003:ADR]
# @RELATION CALLS -> [ADR-0004:ADR]
# @RATIONALE ss-tools manages operations that can modify production Superset instances (dashboard migration, backup, deployment). Unauthenticated or under‑authorized access to these operations is a critical security risk. A dedicated RBAC system ensures that DevOps privileges (manage deployments) are cleanly separated from BI privileges (view dashboards) and that actions are auditable.
# @RATIONALE Local auth (bcrypt + JWT) is the primary path because ss-tools must work in air‑gapped enterprise deployments where external identity providers are unavailable. ADFS SSO is an optional federation layer for organizations that already have Active Directory.
# @RATIONALE Role‑Based Access Control (RBAC) was chosen over Attribute‑Based Access Control (ABAC) because: (a) the system has a small, well‑defined set of operations (deploy, backup, migrate, view), (b) RBAC maps naturally to organizational roles (admin, analyst, operator), (c) ABAC adds complexity without proportional benefit for this scope.
# @REJECTED Delegating all auth to Superset — rejected because ss-tools must operate when Superset is down, and Superset's auth model is designed for BI users, not DevOps operators with cross‑environment privileges.
# @REJECTED OAuth2 social login (Google, GitHub) as primary path — rejected because enterprise deployments require air‑gapped operation. External OAuth providers are unavailable in offline mode.
# @REJECTED Simple API key (no RBAC) — rejected because it cannot express granular permissions (admin vs analyst vs viewer), making auditability and least‑privilege impossible.

## Decision

### Authentication Flow

```
┌──────────┐     POST /api/auth/login     ┌──────────────┐
│  User    │ ──────────────────────────────│   FastAPI    │
│ (Browser)│     {username, password}      │   Backend    │
│          │ ◄──────────────────────────── │              │
│          │     {access_token, refresh}   │  bcrypt +    │
│          │                               │  JWT (HS256) │
└──────────┘                               └──────┬───────┘
                                                  │
                                          ┌───────▼───────┐
                                          │  PostgreSQL   │
                                          │  users table  │
                                          │  roles table  │
                                          └───────────────┘
```

### ADFS Federation (Optional)

- Enabled via `config.json: auth.adfs_enabled = true`
- SAML 2.0 flow through `python3-saml`
- ADFS users mapped to local roles via `adfs_group → ss_tools_role` mapping table
- Federated sessions still receive JWTs (stateless after initial SAML handshake)

### RBAC Model

| Role | Permissions |
|------|-------------|
| `admin` | All: manage users, manage roles, manage plugins, deploy, backup, migrate, view dashboards, view logs |
| `analyst` | View dashboards, run LLM analysis plugins, view reports, view logs (own) |
| `operator` | Deploy dashboards, run migrations, manage backups, view logs |
| `viewer` | View dashboards, view reports |

### Token Design

- **Access token**: JWT (HS256), 15‑minute expiry, contains `user_id`, `roles: list[str]`
- **Refresh token**: opaque random string (SHA‑256), 7‑day expiry, stored hashed in DB
- **Superset API token per environment**: AES‑256‑GCM encrypted, stored in `connection_configs` table
- **Plugin execution token**: JWT, scoped to a single `task_id`, 15‑minute expiry

### Security Constraints

1. Passwords: bcrypt with cost factor 12 (minimum).
2. Rate limiting: 5 failed login attempts per IP per 15 minutes → temporary IP block.
3. Token revocation: admin can revoke all sessions for a user (delete refresh tokens).
4. Audit log: all auth events (login success/failure, role change, token revoke) written to `audit_log` table.
5. Enterprise clean mode: local auth only, ADFS disabled, no external network calls for identity.

### RBAC Enforcement Pattern

```python
# backend/src/api/dependencies.py
from fastapi import Depends, HTTPException

def require_role(required_role: str):
    def dependency(current_user: User = Depends(get_current_user)):
        if required_role not in current_user.roles:
            raise HTTPException(status_code=403, detail="Insufficient permissions")
        return current_user
    return dependency

# Usage in route:
@router.post("/api/dashboards/deploy")
async def deploy(..., user: User = Depends(require_role("operator"))):
    ...
```

# [/DEF:ADR-0005:ADR]
