didi-lot2-backend/backend/services/gateway-auth-layer/didiKeycloak/INDEX.md
2026-07-10 03:39:53 -07:00

362 lines
14 KiB
Markdown

# didiKeycloak - Index
> **Deployment LOCAL (activ)**: Keycloak ruleaza ca un singur container `didi-keycloak` pe masina de deployment. Nu exista cluster SSO / Swarm.
>
> - Imagine: `quay.io/keycloak/keycloak:26.0`, pornit cu `start-dev --import-realm`.
> - Port: `28080` (host) -> `8080` (container), servit sub calea relativa `/auth` (`KC_HTTP_RELATIVE_PATH=/auth`).
> - `KC_HOSTNAME_STRICT=false`, `KC_PROXY_HEADERS=xforwarded` — hostname derivat din headerele proxy-ului din fata.
> - **Doua realm-uri** importate din `realm-import/`: `didi-clients` (useri finali) + `didi-admins` (operatori: admin / moderator / senior_moderator).
> - Temele custom sunt bind-mount-uite din folderul acesta in `/opt/keycloak/themes/`.
> - Master credentials: `admin/admin123` (`KEYCLOAK_ADMIN` / `KEYCLOAK_ADMIN_PASSWORD`).
Serviciul de autentificare si autorizare al platformei DIDI. Bazat pe Keycloak, gestioneaza utilizatori, roluri, grupuri, clienti OAuth2 si token-uri JWT. Include teme custom de login si template-uri email in romana.
**Imagine**: quay.io/keycloak/keycloak:26.0 (container local `didi-keycloak`)
**Container**: didi-keycloak (activ, pe masina de deployment)
**Port**: 28080 (host) -> 8080 (container), sub `/auth`
**Realm-uri**: `didi-clients` (useri) + `didi-admins` (operatori)
**Baza de date**: PostgreSQL `didi-postgres:5432/DIDI` (`KC_DB=postgres`, user `bos_interface`)
---
## Ce face
1. **Autentificare OAuth2/OIDC** -- login, logout, refresh token, SSO
2. **Management utilizatori** -- creare, roluri, grupuri, tier-uri
3. **Emitere token-uri JWT** -- access token (10 min), refresh token, SSO session (2h)
4. **Validare JWT** -- Kong valideaza token-urile emise de Keycloak
5. **Securitate cont** -- brute force (lockout dupa 5 incercari esuate), MFA TOTP, password policy
6. **Deep linking mobil** -- redirectare catre app mobila dupa verificare email
7. **Teme custom** -- login page dark purple, emailuri in romana
---
## Structura fisierelor
```
realm-import/
didi-clients-realm.json -- Configurare completa realm (clienti, roluri, grupuri, utilizatori)
themes/
didi-clients-theme/ -- Tema principala (dark purple)
login/
theme.properties -- Configurare tema login
register.ftl -- Formular inregistrare
login-reset-password.ftl -- Resetare parola
login-verify-email.ftl -- Pagina verificare email
info.ftl -- Routing mobil/web dupa actiuni
register-commons.ftl -- Macro acceptare termeni
messages/
messages_en.properties -- Etichete UI engleza
resources/
css/login.css -- Stil dark purple (784 linii)
js/placeholders.js -- Placeholders formulare
email/
theme.properties -- Configurare tema email
html/
email-verification.ftl -- Template verificare email (romana, dark theme)
executeActions.ftl -- Template actiuni (dark purple gradient)
text/
email-verification.ftl -- Versiune text plain
didi-ai-theme/ -- Tema alternativa (white, blue accents)
login/
theme.properties
resources/
css/login.css
img/logo.png
didi-backend-theme/ -- Tema backend (white, "didi - Backend")
login/
theme.properties
resources/
css/login.css
img/logo.png
```
Zero cod custom backend. Doar configurare realm JSON + teme FreeMarker/CSS.
---
## Clienti OAuth2 (4)
| Client ID | Tip | Scop | Flow-uri | PKCE |
|-----------|-----|------|----------|------|
| didi-web-app | Public | Frontend web utilizatori | Standard + Direct Access | nu |
| admin-dashboard | Public | Dashboard admin React | Standard + Direct Access | S256 |
| orchestrator-api | Confidential | Serviciu backend orchestrator | Direct Access + Service Account | nu |
| kong-api-gateway | Bearer Only | Gateway JWT validation | Service Account only | nu |
### didi-web-app
- Redirect URIs: localhost:3001, localhost:5173, localhost:13001, localhost:33001 (+ 127.0.0.1)
- Web Origins: aceleasi + wildcard
- Scopes: web-origins, acr, profile, roles, email
### admin-dashboard
- Root URL: http://localhost:13003
- PKCE: S256 (obligatoriu)
- Redirect URIs: localhost:13003, localhost:3003, localhost:33003, localhost:33001, localhost:3001, 127.0.0.1:13003, 127.0.0.1:3003, 127.0.0.1:33003, 127.0.0.1:33001, 10.11.50.11:33003, 10.11.50.11:3003
- Post Logout: localhost:13003, localhost:3003, localhost:33003, 10.11.50.11:33003
### orchestrator-api
- Secret: nmmImrmPAcADuPh-ZTqLY7GDhCAjfXsolDOM6TxZbHg
- Service Account: activat
- Bearer Only: implicit (confidential)
### kong-api-gateway
- Secret: Fu1rJ8QsjCj4j4_qZiMXyx6Ewo3xC2ik7X5m_MvSLOE
- Bearer Only: da (nu face login, doar valideaza)
- Service Account: activat
---
## Roluri (doua realm-uri)
Operatorii (admin / moderator / senior_moderator) traiesc in realm-ul **`didi-admins`**; realm-ul **`didi-clients`** contine doar capabilitati de user si tier-uri de abonament.
### Realm `didi-admins` (operatori)
| Rol | Scop |
|-----|------|
| admin | Acces complet la platforma + admin dashboard |
| moderator | HIL moderator -- poate revendica si rezolva intrari din coada (admin dashboard /moderation) |
| senior_moderator | Senior HIL moderator -- poate escalada si forta gold atom in brain |
### Realm `didi-clients` (useri finali)
| Rol | Scop |
|-----|------|
| viewer | Poate vizualiza rezultate analize |
| analyst | Poate crea si gestiona analize |
| api_user | Poate accesa endpoint-uri API |
| free_tier | Privilegii tier gratuit |
| paid_tier | Privilegii tier platit |
| enterprise_tier | Privilegii tier enterprise |
Roluri implicite la inregistrare (didi-clients): viewer + free_tier
---
## Grupuri (6)
| Grup | Roluri | Tier | Limita zilnica | Rate limit |
|------|--------|------|----------------|------------|
| free-users | free_tier, viewer, api_user | free | 10 | 10/min |
| paid-users | paid_tier, viewer, analyst, api_user | paid | 100 | 60/min |
| enterprise-users | enterprise_tier, viewer, analyst, api_user | enterprise | nelimitat | 600/min |
| administrators | admin, analyst, viewer, api_user, enterprise_tier | admin | nelimitat | nelimitat |
| Grup | Roluri | Scop |
|------|--------|------|
| moderators-team | moderator | HIL review staff |
| senior-moderators-team | moderator + senior_moderator | Lead moderators with brain gold-promotion authority |
Atributele de grup (tier, daily_limit, rate_limit) sunt disponibile in token-ul JWT si pot fi folosite de Kong/backend pentru rate limiting.
---
## Acces admin dashboard
| Pagina admin dashboard | viewer / paid_tier / etc | moderator | senior_moderator | admin |
|---|---|---|---|---|
| /admin/* (any) | 403 (Unauthorized page -> public app) | Dashboard + History + Moderation | same + force_gold_brain | tot |
| /users, /framework, /llm-components, /providers | nu | nu | nu | da |
| /history | nu | da | da | da |
| /moderation/* | nu | da | da | da |
Note: `viewer` este rolul implicit asignat la toate signup-urile (`defaultRoles: [viewer, free_tier]`). End-userii (clientii) primesc acest rol; ei NU vad niciodata admin dashboard.
---
## Utilizatori pre-configurati (5)
| Email | Parola | Grup | Rol principal |
|-------|--------|------|---------------|
| admin@didi.local | admin123 | administrators | admin |
| demo@didi.local | Demo123! | free-users | viewer |
| free@didi.local | password123 | free-users | free_tier |
| paid@didi.local | password123 | paid-users | paid_tier |
| enterprise@didi.local | password123 | enterprise-users | enterprise_tier |
Toti au emailVerified: true. Parolele nu sunt temporare.
---
## Setari token
| Parametru | Valoare |
|-----------|---------|
| Access Token Lifespan | 600s (10 minute) |
| Access Token Implicit | 900s (15 minute) |
| SSO Session Idle | 7200s (2 ore) |
| SSO Session Max | 86400s (24 ore) |
| Algoritm semnatura | RS256 |
---
## Securitate
Aplicata pe **ambele realm-uri** (`didi-clients` + `didi-admins`).
### Brute force protection
- Activat (`bruteForceProtected: true`)
- Max incercari esuate: 5 (`failureFactor`)
- Timp asteptare: 60s (increment) / min quick-login wait 60s / quick-login check 1000ms
- Max wait: 900s (15 minute)
- Fereastra glisanta: 43200s (12 ore)
- Lockout permanent: dezactivat
### MFA / TOTP (livrabil Lot 2)
- Politica OTP: `otpPolicyType=totp` (HmacSHA1, 6 cifre, perioada 30s) — pe ambele realm-uri.
- Required action `CONFIGURE_TOTP` **enabled** pe realm-ul `didi-admins` (operatorii sunt fortati sa configureze TOTP; userii noi de admin primesc `CONFIGURE_TOTP` in `requiredActions` la prima logare, alaturi de `UPDATE_PASSWORD`).
- Realm-ul `didi-clients` are politica TOTP configurata (MFA disponibil pentru enrolment).
### Password policy (ambele realm-uri)
```
length(10) and digits(1) and upperCase(1) and lowerCase(1) and notUsername and passwordHistory(3)
```
Minim 10 caractere, cel putin o cifra, o majuscula, o minuscula, parola != username, fara reutilizarea ultimelor 3 parole.
### Setari realm
- Inregistrare: dezactivata (registrationAllowed: false)
- Login cu email: da
- Email ca username: da
- Verificare email: dezactivata (verifyEmail: false)
- Editare username: nu
- Emailuri duplicate: nu
- Remember me: da
- Reset parola: da
---
## Teme
### didi-clients-theme (principala, dark purple)
- Background: #050510 (foarte inchis)
- Accent: #A855F7 -> #7C3AED -> #6D28D9 (gradient purple)
- Card: glassmorphism (backdrop blur, border semi-transparent)
- Logo: "didi" (48px, font Outfit)
- Subtitle: "Misinformation Detection Platform"
- Font: Outfit (display) + Inter (body)
- Butoane: gradient purple cu glow la hover
- Responsive: suporta mobile (100dvh)
### didi-ai-theme (alternativa)
- Background: alb
- Accent: #0052CC (albastru)
- Subtitle: "didi - AI Platform"
### didi-backend-theme (alternativa)
- Background: alb
- Accent: #0052CC (albastru)
- Subtitle: "didi - Backend"
---
## Template-uri email
### email-verification.ftl
- Limba: romana
- Titlu: "Verifica adresa de email"
- Stil: dark purple gradient header
- URL custom: https://didi365.eu/api/auth/verify-email?key=...
- Afiseaza timpul de expirare (convertit din secunde)
- Deep link mobil: didi://email-verified, com.didi365.app://email-verified
### executeActions.ftl
- Stil: dark purple gradient
- Suporta actiuni multiple
- Deep linking mobil
### info.ftl (routing dupa actiuni)
- Detecteaza client ID (didi-mobile-app vs didi-web-app)
- Mobile: deep link cu fallback dupa 1.5-3s
- Web: redirect la /email-verified dupa 2s
- Butoane: "Deschide in aplicatie" / "Continua in browser"
---
## Fluxul de autentificare
```
Utilizator deschide aplicatia
|
v
Redirect la Keycloak login (tema didi-clients-theme)
|
v
Utilizatorul introduce email + parola
|
v
Keycloak valideaza + emite JWT (access token 10 min, refresh token)
|
v
Redirect inapoi la aplicatie cu authorization code
|
v
Aplicatia schimba codul in token-uri (PKCE pentru admin-dashboard)
|
v
Requesturi API cu Authorization: Bearer {access_token}
|
v
Kong valideaza JWT-ul (plugin jwt, consumer didi-keycloak-users, RS256, match pe iss)
|
v
Backend-ul decodeaza JWT pentru user_id/email (fara re-validare)
|
v
La fiecare 30s, aplicatia face refresh token daca expira in < 70s
```
---
## Cum comunica cu restul platformei
| Cine | Ce face | Cum |
|------|---------|-----|
| admin-dashboard | Login/logout utilizator | OAuth2 Standard Flow + PKCE |
| didi-web-app (frontend) | Login/logout utilizator | OAuth2 Standard Flow |
| Kong | Valideaza JWT pe fiecare request (RS256, match pe iss) | plugin jwt + consumer didi-keycloak-users |
| didiFramework (auth.ts) | Auto-inregistrare utilizator, Keycloak Admin API | Direct Access + Admin credentials |
| didiFramework (admin.ts) | Lista utilizatori, update emailVerified | Keycloak Admin API |
| agent-v3 | Decodeaza JWT din header (sub, email) | Doar decodare, fara validare (Kong a validat deja) |
---
## Admin API folosit de automatizari
- Admin API base: `http://localhost:28080/auth/admin/realms/{didi-clients|didi-admins}/` (Keycloak local, sub `/auth`)
- Master token via `POST /auth/realms/master/protocol/openid-connect/token` cu `client_id=admin-cli, username=admin, password=admin123`
- Folosit de fluxul de auto-inregistrare didiFramework + scripturi viitoare de automatizare.
---
## Roluri JWT in token-urile clientilor
Token-ul JWT contine acum array-ul `realm_access.roles`, parsat de agent-v3 (`req.jwtRoles`) pentru verificarile de rol pe endpoint-urile de moderare. Token-ul se reimprospateaza automat la fiecare 30s (comportament existent).
---
## Baza de date
Keycloak foloseste PostgreSQL local, aceeasi instanta ca restul platformei:
- `KC_DB=postgres`
- `KC_DB_URL=jdbc:postgresql://didi-postgres:5432/DIDI` (schema `public`)
- User: `bos_interface`
- Schema proprie Keycloak (gestionata automat)
Datele stocate: realm config, utilizatori, sesiuni, events, client sessions.
---
## Audit si evenimente
- Evenimente utilizator: activate (jboss-logging)
- Evenimente admin: activate cu detalii
- Logare: in stdout Docker (accesibil prin docker logs)
## Recent Changes
- **MFA / TOTP (livrabil Lot 2)**: `otpPolicyType=totp` pe ambele realm-uri; required action `CONFIGURE_TOTP` enabled pe `didi-admins` (operatorii sunt fortati sa configureze TOTP la prima logare, alaturi de `UPDATE_PASSWORD`).
- **Password policy** pe ambele realm-uri: `length(10) and digits(1) and upperCase(1) and lowerCase(1) and notUsername and passwordHistory(3)`.
- **Realm `didi-admins` (operatori)**: 3 roluri `admin` / `moderator` / `senior_moderator`; clienti publici `admin-dashboard` + `ai-platform-dashboard`; useri de test `moderator.test@didi.local`, `senior.moderator.test@didi.local`.
- **Realm `didi-clients` (useri finali)**: capabilitati `viewer`, `analyst`, `api_user` + tier-uri `free_tier`, `paid_tier`, `enterprise_tier`; clienti `didi-web-app`, `admin-dashboard`, `orchestrator-api`, `kong-api-gateway`.
- **Deployment local**: container unic `didi-keycloak` (`quay.io/keycloak/keycloak:26.0`, `start-dev --import-realm`), port `28080` sub `/auth`, `KC_HOSTNAME_STRICT=false`, `KC_PROXY_HEADERS=xforwarded`, DB `didi-postgres:5432/DIDI`. Fara cluster SSO / Swarm / Infinispan.