Initial commit
This commit is contained in:
@@ -0,0 +1,27 @@
|
|||||||
|
# Configurazione per docker-compose (postgres + backend + frontend + keycloak)
|
||||||
|
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=postgres
|
||||||
|
POSTGRES_DB=scouthub
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
ATTIVITA_BACKEND_PORT=8080
|
||||||
|
|
||||||
|
# Deve restare 8080: il frontend Angular ha l'URL dell'API hardcoded
|
||||||
|
# in src/environments/environment.ts (apiUrl: 'http://localhost:8080')
|
||||||
|
ATTIVITA_FRONTEND_PORT=4200
|
||||||
|
|
||||||
|
KEYCLOAK_DB_PASSWORD=keycloak_change_me
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD=admin_change_me
|
||||||
|
|
||||||
|
# Se in locale esegui anche scouthub-home-be fuori da Docker (npm run dev),
|
||||||
|
# il suo PORT di default (8082) è già scelto per non collidere con questo.
|
||||||
|
KEYCLOAK_PORT=8081
|
||||||
|
|
||||||
|
# Deve restare 8082: scouthub-home-fe ha l'URL dell'org-service hardcoded
|
||||||
|
# in src/environments/environment.ts (orgServiceApiBaseUrl: 'http://localhost:8082')
|
||||||
|
HOME_BACKEND_PORT=8082
|
||||||
|
HOME_FRONTEND_PORT=4201
|
||||||
|
|
||||||
|
# Deve coincidere con il secret del client "scouthub-home-be" in keycloak/realm-export.json
|
||||||
|
KEYCLOAK_ORG_SERVICE_CLIENT_SECRET=change_me
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- scouthub-home-be usa un database separato sulla stessa istanza Postgres di "db".
|
||||||
|
-- Eseguito solo al primo avvio del container (volume dati vuoto).
|
||||||
|
SELECT 'CREATE DATABASE scouthub_home'
|
||||||
|
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'scouthub_home')
|
||||||
|
\gexec
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB}
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_PORT}:5432"
|
||||||
|
volumes:
|
||||||
|
- scouthub_db_data:/var/lib/postgresql/data
|
||||||
|
# Crea anche il DB scouthub_home usato da scouthub-home-be (solo al primo init).
|
||||||
|
- ./db-init:/docker-entrypoint-initdb.d:ro
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
attivita-backend:
|
||||||
|
build:
|
||||||
|
context: ./scouthub-attivita-be
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PORT: ${ATTIVITA_BACKEND_PORT}
|
||||||
|
CORS_ORIGIN: http://localhost:${ATTIVITA_FRONTEND_PORT}
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?schema=public
|
||||||
|
KEYCLOAK_BASE_URL: http://keycloak:8080
|
||||||
|
KEYCLOAK_REALM: scouthub
|
||||||
|
ports:
|
||||||
|
- "${ATTIVITA_BACKEND_PORT}:${ATTIVITA_BACKEND_PORT}"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
keycloak:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
|
attivita-frontend:
|
||||||
|
build:
|
||||||
|
context: ./scouthub-attivita-fe
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${ATTIVITA_FRONTEND_PORT}:80"
|
||||||
|
depends_on:
|
||||||
|
- attivita-backend
|
||||||
|
|
||||||
|
home-backend:
|
||||||
|
build:
|
||||||
|
context: ./scouthub-home-be
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
PORT: ${HOME_BACKEND_PORT}
|
||||||
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/scouthub_home?schema=public
|
||||||
|
FRONTEND_BASE_URL: http://localhost:${HOME_FRONTEND_PORT}
|
||||||
|
# Rete interna Docker: la validazione del JWT (JWKS) non controlla l'issuer,
|
||||||
|
# quindi non serve che coincida con l'hostname visto dal browser (localhost:8081).
|
||||||
|
KEYCLOAK_BASE_URL: http://keycloak:8080
|
||||||
|
KEYCLOAK_REALM: scouthub
|
||||||
|
KEYCLOAK_ORG_SERVICE_CLIENT_ID: scouthub-home-be
|
||||||
|
KEYCLOAK_ORG_SERVICE_CLIENT_SECRET: ${KEYCLOAK_ORG_SERVICE_CLIENT_SECRET}
|
||||||
|
ports:
|
||||||
|
- "${HOME_BACKEND_PORT}:${HOME_BACKEND_PORT}"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
keycloak:
|
||||||
|
condition: service_started
|
||||||
|
|
||||||
|
home-frontend:
|
||||||
|
build:
|
||||||
|
context: ./scouthub-home-fe
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "${HOME_FRONTEND_PORT}:80"
|
||||||
|
depends_on:
|
||||||
|
- home-backend
|
||||||
|
|
||||||
|
keycloak-db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: keycloak
|
||||||
|
POSTGRES_USER: keycloak
|
||||||
|
POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- scouthub_keycloak_db_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
keycloak:
|
||||||
|
image: quay.io/keycloak/keycloak:26.7
|
||||||
|
restart: unless-stopped
|
||||||
|
# --import-realm importa keycloak/realm-export.json solo se il realm non esiste già
|
||||||
|
# NOTA: dopo l'import, assegnare al service account di scouthub-home-be i client role
|
||||||
|
# del client 'realm-management': manage-organizations, manage-users, manage-groups,
|
||||||
|
# view-users (permessi minimi, non manage-realm). Con Fine-Grained Admin Permissions
|
||||||
|
# (26.7+, feature admin-fine-grained-authz:v1) si puo' poi restringere ulteriormente
|
||||||
|
# per singola Organization.
|
||||||
|
command: start-dev --import-realm
|
||||||
|
environment:
|
||||||
|
KC_DB: postgres
|
||||||
|
KC_DB_URL: jdbc:postgresql://keycloak-db:5432/keycloak
|
||||||
|
KC_DB_USERNAME: keycloak
|
||||||
|
KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
|
||||||
|
KEYCLOAK_ADMIN: admin
|
||||||
|
KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
|
||||||
|
# admin-fine-grained-authz:v1 serve per i permessi granulari sulle Organization (26.7+).
|
||||||
|
# Verificare con `kc.sh show-config` che i flag richiesti siano invariati nella versione
|
||||||
|
# effettivamente usata: i nomi dei feature flag cambiano tra minor version di Keycloak.
|
||||||
|
KC_FEATURES: organization,admin-fine-grained-authz:v1
|
||||||
|
KC_HOSTNAME: localhost
|
||||||
|
KC_HOSTNAME_PORT: "${KEYCLOAK_PORT}"
|
||||||
|
KC_HTTP_ENABLED: "true"
|
||||||
|
ports:
|
||||||
|
- "${KEYCLOAK_PORT}:8080"
|
||||||
|
volumes:
|
||||||
|
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro
|
||||||
|
depends_on:
|
||||||
|
- keycloak-db
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
scouthub_db_data:
|
||||||
|
scouthub_keycloak_db_data:
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# keycloak/realm-export.json
|
||||||
|
|
||||||
|
Realm `scouthub` con feature Organizations abilitata, importato automaticamente
|
||||||
|
all'avvio di Keycloak (`--import-realm` nel `docker-compose.yml` alla radice).
|
||||||
|
|
||||||
|
Basato su `keycloak/realm.json` (bozza di riferimento), con l'aggiunta del
|
||||||
|
ruolo `admin-centrale` richiesto da `POST /gruppi` in `scouthub-home-be`
|
||||||
|
(placeholder temporaneo, vedi il TODO in `src/routes/gruppi.routes.ts`).
|
||||||
|
|
||||||
|
Contiene già:
|
||||||
|
|
||||||
|
- i realm role usati dal backend: `admin-centrale`, `capo-gruppo`,
|
||||||
|
`capo-unita`, `censito`, più il placeholder `manage-organizations`
|
||||||
|
- il client scope `organization` (aggiunge id/attributi della Organization
|
||||||
|
nei token OIDC)
|
||||||
|
- il client confidential `scouthub-home-be` (service account abilitato,
|
||||||
|
usato dal backend per il flow client-credentials verso le Admin REST API —
|
||||||
|
il suo `clientId`/`secret` devono corrispondere a
|
||||||
|
`KEYCLOAK_ORG_SERVICE_CLIENT_ID`/`_SECRET` in `scouthub-home-be/.env.example`)
|
||||||
|
- il client pubblico `scouthub-frontend` (login utente, redirect su
|
||||||
|
`http://localhost:4200/*`)
|
||||||
|
|
||||||
|
Passi manuali ancora da fare dopo l'import (non automatizzabili in un realm
|
||||||
|
export senza conoscere gli id generati a runtime):
|
||||||
|
|
||||||
|
- assegnare al service account di `scouthub-home-be` i client role del
|
||||||
|
client `realm-management`: `manage-organizations`, `manage-users`,
|
||||||
|
`manage-groups`, `view-users` (permessi minimi, non `manage-realm`). Con le
|
||||||
|
Fine-Grained Admin Permissions (26.7+, `admin-fine-grained-authz:v1`, già
|
||||||
|
abilitata via `KC_FEATURES`) si può poi restringere ulteriormente per
|
||||||
|
singola Organization
|
||||||
|
- eventuali mapper aggiuntivi sui client per garantire che `email`,
|
||||||
|
`realm_access.roles` e `organization` compaiano nel token come atteso da
|
||||||
|
`src/middleware/authenticate.ts` in `scouthub-home-be` (i default di
|
||||||
|
Keycloak per organization scope e realm roles di solito bastano, ma vanno
|
||||||
|
verificati contro la versione effettivamente in uso)
|
||||||
|
|
||||||
|
I passaggi da fare sono:
|
||||||
|
1. Apri http://localhost:8081/admin e fai login (admin / admin, realm master).
|
||||||
|
2. In alto a sinistra, cambia realm da master a scouthub.
|
||||||
|
3. Menu laterale → Clients → clicca su scouthub-home-be.
|
||||||
|
4. Vai sul tab "Service account roles" (visibile perché il client ha "Service accounts enabled").
|
||||||
|
5. Clicca "Assign role".
|
||||||
|
6. Nella finestra che si apre, in alto c'è un filtro impostato su "Filter by realm roles" — cambialo in "Filter by clients".
|
||||||
|
7. Cerca/seleziona il client realm-management.
|
||||||
|
8. Spunta questi ruoli — attenzione: ho già controllato via API l'elenco reale dei client role disponibili su realm-management in questa istanza Keycloak 26.7, e manage-groups non esiste come ruolo separato in questa versione (probabilmente
|
||||||
|
la gestione gruppi è coperta da manage-users). Quindi vedrai solo questi 3, spuntali tutti:
|
||||||
|
- manage-organizations
|
||||||
|
- manage-users
|
||||||
|
- view-users
|
||||||
|
9. Clicca Assign.
|
||||||
|
10. Dopo fatto questo bisogna fare un user admin-centrale
|
||||||
|
|
||||||
|
I passaggi da fare per admin-centrale:
|
||||||
|
1. Apri http://localhost:8081/admin, login admin/admin, cambia realm in scouthub.
|
||||||
|
2. Menu laterale → Users → clicca su movioletto@yahoo.it.
|
||||||
|
3. Vai sul tab "Role mapping".
|
||||||
|
4. Clicca "Assign role".
|
||||||
|
5. Assicurati che il filtro sia su "Filter by realm roles" (dovrebbe esserlo di default per gli utenti normali).
|
||||||
|
6. Cerca e seleziona admin-centrale.
|
||||||
|
7. Clicca Assign.
|
||||||
|
|
||||||
|
⚠️ Il secret del client `scouthub-home-be` (`CAMBIA-QUESTO-SECRET-IN-UN-VAULT`)
|
||||||
|
è un placeholder di sviluppo committato in chiaro, coerente con le altre
|
||||||
|
credenziali dev del progetto (vedi `.env` alla radice): da sostituire con un
|
||||||
|
segreto reale gestito a parte prima di qualunque uso condiviso o di
|
||||||
|
produzione.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"realm": "scouthub",
|
||||||
|
"enabled": true,
|
||||||
|
"organizationsEnabled": true,
|
||||||
|
"sslRequired": "external",
|
||||||
|
"registrationAllowed": true,
|
||||||
|
"registrationEmailAsUsername": true,
|
||||||
|
"loginWithEmailAllowed": true,
|
||||||
|
"resetPasswordAllowed": true,
|
||||||
|
"verifyEmail": false,
|
||||||
|
|
||||||
|
"roles": {
|
||||||
|
"realm": [
|
||||||
|
{ "name": "admin-centrale", "description": "Placeholder temporaneo: crea nuovi gruppi scout (Organization). Vedi TODO in src/routes/gruppi.routes.ts" },
|
||||||
|
{ "name": "capo-gruppo", "description": "Gestisce il proprio gruppo scout (Organization): membri, inviti, ruoli" },
|
||||||
|
{ "name": "capo-unita", "description": "Gestisce attivita' e materiali della propria branca" },
|
||||||
|
{ "name": "censito", "description": "Accesso in sola consultazione" },
|
||||||
|
{ "name": "manage-organizations", "description": "Placeholder locale: il ruolo reale e' il client role manage-organizations su realm-management" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"clients": [
|
||||||
|
{
|
||||||
|
"clientId": "scouthub-home-be",
|
||||||
|
"name": "Servizio di gestione gruppi scout (org-service)",
|
||||||
|
"enabled": true,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"publicClient": false,
|
||||||
|
"standardFlowEnabled": false,
|
||||||
|
"directAccessGrantsEnabled": false,
|
||||||
|
"serviceAccountsEnabled": true,
|
||||||
|
"clientAuthenticatorType": "client-secret",
|
||||||
|
"secret": "CAMBIA-QUESTO-SECRET-IN-UN-VAULT",
|
||||||
|
"attributes": {
|
||||||
|
"note": "Usato solo server-to-server dal backend org-service verso le Admin REST API. Non esporre mai il secret al frontend."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientId": "scouthub-frontend",
|
||||||
|
"name": "Frontend Angular Scouthub",
|
||||||
|
"enabled": true,
|
||||||
|
"protocol": "openid-connect",
|
||||||
|
"publicClient": true,
|
||||||
|
"standardFlowEnabled": true,
|
||||||
|
"directAccessGrantsEnabled": false,
|
||||||
|
"redirectUris": [
|
||||||
|
"http://localhost:4200/*",
|
||||||
|
"http://localhost:4201/*"
|
||||||
|
],
|
||||||
|
"webOrigins": [
|
||||||
|
"http://localhost:4200",
|
||||||
|
"http://localhost:4201"
|
||||||
|
],
|
||||||
|
"defaultClientScopes": [
|
||||||
|
"openid",
|
||||||
|
"basic",
|
||||||
|
"roles",
|
||||||
|
"profile",
|
||||||
|
"email",
|
||||||
|
"organization"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user