Proof of concept per architettura centralizzata gestione soci e SSO per i soci di fedimedia. https://www.fedimedia.it
Find a file
2026-02-11 15:05:56 +01:00
.aider.tags.cache.v4 file .env esterno 2026-02-10 17:39:30 +01:00
authelia-config refactor: usa variabili d'ambiente per la configurazione di Authelia 2026-02-10 17:35:08 +01:00
nginx first push 2026-02-10 17:20:22 +01:00
php fix: correggi sintassi e implementa logica cURL in sync_ldap.php 2026-02-10 17:30:46 +01:00
wp-content/plugins/fedimedia-custom first push 2026-02-10 17:20:22 +01:00
.aider.chat.history.md file .env esterno 2026-02-10 17:39:30 +01:00
.aider.input.history file .env esterno 2026-02-10 17:39:30 +01:00
.env.template refactor: usa variabili d'ambiente per la configurazione di Authelia 2026-02-10 17:35:08 +01:00
.gitignore chore: esternalizza configurazione lldap in .env 2026-02-10 17:34:54 +01:00
docker-compose.yml refactor: usa variabili d'ambiente per la configurazione di Authelia 2026-02-10 17:35:08 +01:00
LICENSE Initial commit 2026-02-10 17:05:40 +01:00
README.md fix architettura 2026-02-11 15:05:56 +01:00

fedimedia-soci

Proof of concept per architettura centralizzata gestione soci e SSO per i soci di fedimedia.

Per ora si tratta soltanto di appunti non testati, un brainstorming insomma.

Anche questa documentazione è in fase di stesura e correzione.

Architettura

  • Viene usato lldap (ldap leggero scritto in rust) come database centralizzato per gli utenti (= soci associazione).
  • Authelia gestirà SSO per le singole applicazioni e anche il reset password per gli untenti.
  • CiviCRM installato su wordpress sarà il portale deddicata alla gestione dell'associazione, che scriverà le informazioni su lldap (socio attivo quella più importante)

Esperienza utente

Riassunto dell'esperienza Utente/Socio:

  • Iscrizione: Il socio paga su WordPress/CiviCRM.
  • Benvenuto: Riceve una mail con: "Benvenuto in Fedimedia! Il tuo account è attivo. User: mario.rossi, Pass: 1234abc. Accedi qui: auth.fedimedia.it".
  • Primo Accesso: Il socio entra, Authelia lo riconosce tramite LLDAP.

Dimenticanza: Se perde la password, usa il tasto "Forgot password" su Authelia. Riceve una mail, la cambia, e istantaneamente la nuova password funziona per Nextcloud, Matrix e Email.

Implementazione tecnica

Creiamo un docker compose per server ldap (LLDAP) e authelia

mkdir fedimedia-auth && cd fedimedia-auth
mkdir lldap-data authelia-config

Configurazione Variabili d'Ambiente (.env)

Prima di avviare i container, è necessario configurare le password e i parametri sensibili. Copia il file template per creare il tuo file .env:

cp .env.template .env

Modifica il file .env inserendo password sicure e i parametri corretti per il tuo ambiente.

Nota su Authelia: La configurazione principale di Authelia risiede nel file authelia-config/configuration.yml. Questo file è configurato per leggere le password (come quella di admin LDAP) direttamente dalle variabili d'ambiente definite nel file .env.

Vedi file docker-compose.yml

docker compose up -d

tunnel ssh per porta 17170 (oppure protetto da reverse proxy nginx)

Configurazioni iniziali server ldap

apri browser http://localhost:17170 Username: admin Password: admin_password_fedimedia (quella impostata nel compose).

A. Creazione Gruppi

Vai nella sezione Groups e crea i due gruppi fondamentali per la logica che abbiamo discusso:

Clicca su "Create Group" -> Name: soci_attivi
Clicca su "Create Group" -> Name: consiglio_direttivo

B. Creazione Primo Utente (Il tuo utente di test)

Vai nella sezione Users -> "Create User":

ID: mario.rossi
Email: mario@fedimedia.it
Display Name: Mario Rossi
Dopo averlo creato, clicca sull'utente e premi "Set Password" per dargli una password iniziale.

C. Assegnazione ai Gruppi

Sempre nella scheda dell'utente mario.rossi:

Vai in "Groups" e aggiungilo a soci_attivi.

nginx reverse proxy

Vedi file nginx/auth.fedimedia.it.conf

Collegare Wordpress ad Authelia (Login SSO)

nel file `configuration.yml' di Authelia:

identity_providers:
  oidc:
    clients:
      - id: wordpress_fedimedia
        description: Sito Web Fedimedia
        secret: '$argon2id$v=19$m=65536,t=3,p=4$...' # Genera un hash segreto
        public: false
        authorization_policy: one_factor
        redirect_uris:
          - https://fedimedia.it/wp-admin/admin-ajax.php?action=openid-connect-authorize
        scopes: [openid, profile, groups, email]
        userinfo_signed_response_alg: 'none'

In WordPress: Installa il plugin "OpenID Connect Generic" e configuralo così:

CiviCRM e LLDAP

Per automatizzare l'inserimento nel gruppo soci_attivi, useremo l'estensione CiviRules.

  1. Installa le estensioni: CiviRules e CiviCRM Webhook (o un'estensione per chiamate API).
  2. Crea una Regola:
    • Trigger: "Membership is added or changed".
    • Linked Condition: "Membership Status is 'New' or 'Current'".
    • Action: "Execute Custom PHP" (oppure un Webhook verso uno script).

Esempio di logica dello script (PHP) da far girare in CiviCRM: Questo script invia una chiamata a LLDAP per aggiungere l'utente al gruppo:

// Esempio logica chiamando l'API GraphQL di LLDAP
$username = $contact->external_identifier; // o il campo scelto
$query = 'mutation { addUserToGroup(userId: "'.$username.'", groupId: 1) { ok } }';
// Invia la richiesta cURL a http://lldap:17170/graphql

Procedura per disabilitare soci non più attivi

// Esegui questo script per allineare tutto a inizio anno
$expired_members = civicrm_api3('Membership', 'get', [
    'sequential' => 1,
    'status_id' => "Expired", // Prende tutti i soci scaduti
    'return' => ["contact_id"],
]);

foreach ($expired_members['values'] as $member) {
    $username = civicrm_api3('Contact', 'getvalue', [
        'return' => "external_identifier",
        'id' => $member['contact_id'],
    ]);
    
    sync_to_lldap($username, 'remove');
    echo "Rimosso l'accesso per: $username\n";
}

Sincronizzazione CiviCRM e LLDAP

Vedi php/sync_lldap.php

Attivazione automatica (Hook di CiviCRM)

Per far sì che questo script venga eseguito da solo ogni volta che un socio viene approvato o scade, usiamo gli Hooks di CiviCRM. Aggiungi questo nel tuo modulo personalizzato o nel file dei template del CMS:

/**
 * Questo hook intercetta il cambio di stato della Membership
 */
function fedimedia_civicrm_post($op, $objectName, $objectId, &$objectRef) {
    if ($objectName === 'Membership' && ($op === 'create' || $op === 'edit')) {
        
        // Recuperiamo lo username del socio (usando l'External ID del contatto)
        $contactId = $objectRef->contact_id;
        $username = civicrm_api3('Contact', 'getvalue', [
            'return' => "external_identifier", 
            'id' => $contactId,
        ]);

        // Verifichiamo lo stato (ID 1 = New, ID 2 = Current)
        $statusId = $objectRef->status_id;

        if ($statusId == 1 || $statusId == 2) {
            // Socio attivo: lo aggiungiamo su LLDAP
            sync_to_lldap($username, 'add');
        } else {
            // Qualsiasi altro stato (Expired, Cancelled, ecc.): lo rimuoviamo
            sync_to_lldap($username, 'remove');
        }
    }
}

Note

Importante per il setup:

  • External Identifier: In CiviCRM, assicurati di inserire nel campo "Identificativo esterno" del socio lo stesso username che useranno in LLDAP (es: mario.rossi). Questo è il "gancio" che unisce i due sistemi.

  • Sicurezza: Poiché lo script gira sul server, usa l'IP interno di Docker per comunicare con LLDAP (es. http://lldap:17170) così non devi esporre le API di LLDAP su internet.

Creazine nuovi soci

Flusso in CiviCRM:

  1. L'utente si iscrive.
  2. L'Hook intercetta la creazione: chiama create_lldap_user.
  3. CiviCRM invia una mail di benvenuto al socio includendo lo username e la password generata.
  4. Consiglio: Nella mail, scrivi: "Per motivi di sicurezza, cambia la password al primo accesso su https://auth.fedimedia.it".

Reset password

Non ha senso gestire il reset della password in CiviCRM o WordPress, perché Authelia è il "portale d'ingresso" e ha già tutto il sistema pronto.

Come funziona il Reset su Authelia:

  1. Il socio va su https://auth.fedimedia.it.
  2. Clicca su "Forgot password?".
  3. Inserisce la sua email (che Authelia verificherà su LLDAP).
  4. Authelia invia un link di reset all'indirizzo email del socio.
  5. Il socio clicca, inserisce la nuova password e Authelia aggiorna direttamente LLDAP.

Modificato il configuration.yaml di Authelia con la parte notifier (vedi sopra)

Modifica email socio

CiviCRM Hook

Creiamo un plugin custom per wordpress Vedi file wp-content/plugins/fedimedia-custom/fedimedia-custom.php

Note per l'uso:

  • Attivazione: Vai nel pannello Admin di WordPress -> Plugin e attiva "Fedimedia LLDAP Sync".
  • Identificativo Esterno: Ricordati che CiviCRM non conosce lo "username" di LLDAP a meno che tu non lo scriva nel campo External ID (Identificativo Esterno) del contatto. Se quel campo è vuoto, lo script non farà nulla.
  • Sicurezza: Lo script usa wp_remote_post. Se LLDAP e WordPress sono su server diversi, assicurati che il firewall permetta la comunicazione sulla porta 17170.
  • Password: Ho inserito un commento dove inserire wp_mail. È fondamentale avvisare il socio della creazione dell'account, altrimenti avrà una password che non conosce.

Esempio di pagina limitata a utenti soci_attivi

Esempio di configurazione nginx che limita accesso ai soli soci attivi

# 1. Endpoint di verifica interna
location /authelia {
    internal;
    set $upstream_authelia http://127.0.0.1:9091/api/verify;
    proxy_pass $upstream_authelia;
    proxy_set_header Host auth.fedimedia.it;
    proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

# 2. Protezione della location principale
location / {
    auth_request /authelia; # Attiva la protezione
    
    # Se non è loggato, rimandalo al portale auth.fedimedia.it
    error_page 401 =302 https://auth.fedimedia.it/?rd=$scheme://$http_host$request_uri;

    proxy_pass http://IP_DEL_TUO_NEXTCLOUD; 
    # ... altre config proxy solite ...
}

Prossimi passi

  • Backup di quanto implementato
  • Test funzionali di funzionamento
    • nuovo socio
    • rinnovo
    • cambio email
  • provare CiviCRM
  • email server per i soci (casella cifrata e2ee)
  • account matrix con OIDC

Appunti da sistemare

Casella email per soci

Nel caso volessimo fornire una casella email a ciascun socio, potremmo usare la soluzione seguente.

Useremo stalwart come mail server, e snappymail come webmail, l'autenticazioen sarà sempre centralizzata usando lldap e authelia.

SnappyMail con Authelia (SSO)

Configuriamo SnappyMail per fidarsi delle intestazioni inviate dal tuo Reverse Proxy.

Il flusso sarà: 1. L'utente va su webmail.fedimedia.it. 2. Authelia intercetta la richiesta, chiede il login e verifica su LLDAP. 3. Una volta loggato, Authelia passa l'username a SnappyMail tramite un header (es. X-Remote-User). 4. SnappyMail, configurato in modalità "Automatic Login", accede alla casella IMAP di Stalwart usando una "master key" o fidandosi del proxy.

Configurazione Nginx (Snippet): Nel server block della webmail, aggiungerai:

webmail.fedimedia.it

location / {
    # 1. Chiedi ad Authelia chi è l'utente
    auth_request /authelia;
    auth_request_set $user $upstream_http_remote_user;

    # 2. CANCELLA l'header se il furbo ci ha provato dal browser
    proxy_set_header X-Remote-User ""; 

    # 3. IMPOSTA l'header prendendolo solo da Authelia
    proxy_set_header X-Remote-User $user;

    proxy_pass http://container_snappymail;
}

Credenziali IMAP/SMTP per i soci

Per l'uso su smartphone o Outlook (dove non c'è il browser e quindi non c'è Authelia), il socio userà:

Username: La sua email (mario@fedimedia.it) o il suo uid (mario.rossi).

Password: La stessa password che ha su LLDAP.

Perché funziona? Perché configureremo Stalwart affinché interroghi LLDAP ogni volta che riceve un tentativo di connessione IMAP/SMTP. Stalwart agisce come un "client" che chiede a LLDAP: "Ehi, Mario Rossi vuole entrare con questa password, è corretta?". LLDAP risponde sì/no. 3. Disattivazione temporanea (Socio moroso)

Questa è la parte più elegante del tuo setup. Poiché abbiamo deciso che Stalwart legge gli utenti da LLDAP tramite un filtro, la disattivazione è automatica e avviene nel momento in cui il socio non è più considerato "attivo" in CiviCRM. Diremo a Stalwart di vedere solo quelli nel gruppo giusto:

[directory.lldap.search]
filter = "(&(objectClass=person)(memberOf=cn=soci_attivi,ou=groups,dc=fedimedia,dc=it))"

Cosa succede quando il socio scade?

CiviCRM (tramite il plugin PHP che abbiamo creato) rimuove il socio dal gruppo soci_attivi su LLDAP.

Stalwart aggiorna la sua lista utenti. Non trovando più mario.rossi nel gruppo autorizzato, Stalwart smetterà di riconoscere quell'utente.

Risultato: * Il socio non può più fare login IMAP/SMTP (la password risulterà "errata").

    La Webmail (Authelia) gli negherà l'accesso.

    Importante: Le email già presenti sul server non vengono cancellate, rimangono lì "congelate" finché il socio non rinnova e viene riaggiunto al gruppo.

In alternativa: La soluzione per la "Conservazione": Se vuoi che le email continuino ad arrivare "nel limbo" in attesa del rinnovo, dobbiamo cambiare strategia. Invece di far sparire l'utente, useremo un attributo di LLDAP (o un secondo gruppo) per disabilitare solo il login. In Stalwart: Configureremo il filtro di ricerca per trovare tutti i soci (anche quelli scaduti), ma useremo un filtro per l'autenticazione che permette il login solo a chi è nel gruppo soci_attivi. Risultato: Le email continuano ad arrivare nella casella (il socio non perde nulla), ma il socio non può né vederle né inviarle finché non paga. Appena rinnova, accede e trova tutto lo storico.

IMAP per i soci: La password di LLDAP

Per i client mobili (K-9 Mail, Thunderbird, Apple Mail), non si usa il sistema degli header.

Il socio inserisce la sua email e la sua password di LLDAP.
Stalwart riceve la richiesta e chiede a LLDAP: "L'utente mario ha questa password ed è nel gruppo soci_attivi?"
Se il socio è moroso (fuori dal gruppo), LLDAP risponde "No" o "Accesso negato", anche se la password è corretta.