91 lines
3.4 KiB
Markdown
91 lines
3.4 KiB
Markdown
# TJWater Authentication and Metadata Management
|
|
|
|
## Ownership
|
|
|
|
Keycloak owns login identity, credentials, token issuance, and token expiry.
|
|
TJWater metadata stores only business snapshots and authorization data:
|
|
|
|
- `users.keycloak_id` is the stable identity binding.
|
|
- `users.username`, `users.email`, and `users.last_login_at` are Keycloak claim caches.
|
|
- `users.role`, `users.is_active`, and `users.is_superuser` control TJWater system access.
|
|
- `user_project_membership.project_role` controls project access.
|
|
|
|
The backend does not accept passwords, does not issue local JWTs, and does not
|
|
trust frontend-supplied user IDs.
|
|
|
|
## Login Snapshot Refresh
|
|
|
|
Every authenticated metadata-user resolution validates the Keycloak access token
|
|
and reads `sub`, `preferred_username` or `username`, and `email` claims. The
|
|
backend finds `users` by `keycloak_id = sub`, rejects inactive or missing users,
|
|
then refreshes `username`, `email`, and `last_login_at`.
|
|
|
|
This keeps local display data current without changing the identity binding.
|
|
There is no Keycloak webhook requirement; second-level user or permission sync is
|
|
out of scope unless explicitly requested later.
|
|
|
|
## Admin APIs
|
|
|
|
All admin APIs require metadata admin access: `users.is_superuser = true` or
|
|
`users.role = 'admin'`.
|
|
|
|
User and membership management:
|
|
|
|
- `GET /api/v1/admin/me`
|
|
- `POST /api/v1/admin/users/sync`
|
|
- `POST /api/v1/admin/users/sync/batch`
|
|
- `GET /api/v1/admin/users`
|
|
- `GET /api/v1/admin/users/{user_id}`
|
|
- `PATCH /api/v1/admin/users/{user_id}`
|
|
- `GET /api/v1/admin/projects/{project_id}/members`
|
|
- `POST /api/v1/admin/projects/{project_id}/members`
|
|
- `PATCH /api/v1/admin/projects/{project_id}/members/{user_id}`
|
|
- `DELETE /api/v1/admin/projects/{project_id}/members/{user_id}`
|
|
|
|
Project configuration:
|
|
|
|
- `GET /api/v1/admin/projects`
|
|
- `POST /api/v1/admin/projects`
|
|
- `PATCH /api/v1/admin/projects/{project_id}`
|
|
- `GET /api/v1/admin/projects/{project_id}/databases`
|
|
- `PUT /api/v1/admin/projects/{project_id}/databases`
|
|
- `DELETE /api/v1/admin/projects/{project_id}/databases/{db_role}`
|
|
- `POST /api/v1/admin/projects/{project_id}/databases/{db_role}/health`
|
|
|
|
## Secret Handling
|
|
|
|
Admins submit plaintext DSNs only through HTTPS admin APIs. Operators should not
|
|
write encrypted columns manually.
|
|
|
|
- `project_databases.dsn_encrypted` is encrypted with `DATABASE_ENCRYPTION_KEY`.
|
|
- Admin responses return only `has_dsn`.
|
|
- Audit logs record whether a secret was updated, but never store plaintext DSNs
|
|
or other secrets.
|
|
|
|
Generate the database encryption key with:
|
|
|
|
```bash
|
|
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
```
|
|
|
|
Keep keys stable for the lifetime of encrypted metadata. Rotating a key requires
|
|
decrypting with the old key and re-encrypting with the new key.
|
|
|
|
## Metadata Schema Patches
|
|
|
|
Apply metadata patches in order:
|
|
|
|
1. `resources/sql/004_metadata_auth_management.sql`
|
|
2. `resources/sql/005_metadata_project_configuration.sql`
|
|
|
|
`004` creates Keycloak-backed metadata users and project memberships. `005`
|
|
creates project and project database routing tables with uniqueness, role/type,
|
|
and pool-size constraints.
|
|
|
|
## Frontend System Management
|
|
|
|
`/system-admin` is shown only after `GET /api/v1/admin/me` confirms metadata
|
|
admin access. The page lets admins maintain metadata users, project members,
|
|
projects, project database routing for `biz_data` and `iot_data`, connection
|
|
health checks. This replaces direct SQL editing for normal project onboarding.
|