# 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.