italia / spid-cie-php

Software Development Kit for easy SPID/CIE access integration with simplesamlphp - developed and mantained by Michele D'Amico @damikael
https://italia.github.io/spid-cie-php/
Apache License 2.0
83 stars 39 forks source link
cie php saml simplesamlphp spid
SPID

Minimum PHP Version Join the #spid-php channel Get invited SPID on forum.italia.it SP SPID in produzione con spid-php

spid-cie-php

Software Development Kit for easy SPID & CIE access integration with SimpleSAMLphp.\ spid-php has been developed and is maintained by Michele D'Amico (@damikael). It's highly recommended to use the latest release.

spid-php video tutorial

spid-php è uno script composer (https://getcomposer.org/) che semplifica e automatizza il processo di installazione e configurazione di SimpleSAMLphp (https://simplesamlphp.org/) per l'integrazione dell'autenticazione SPID e CIE all'interno di applicazioni PHP. spid-php permette di realizzare un Service Provider (pubblico o privato) per SPID e/o CIE in pochi secondi, ma non è orientato alla realizzazione di Aggregatori e/o Gestori.

Si raccomanda di mantenere sempre aggiornata la propria installazione all'ultima versione.

Durante il processo di setup lo script richiede l'inserimento delle seguenti informazioni:

e si occupa di eseguire i seguenti passi:

Al termine del processo di setup si potranno scaricare i metadata oppure utilizzare i certificato X.509 creati nella directory /cert per registrare il service provider sull'ambiente di test/validazione.

Se si è scelto di copiare i file di esempio, sarà possibile verificare subito l'integrazione accedendo da web a /login.php.

Se si è scelto di copiare i file di esempio come proxy, sarà possibile verificare il funzionamento come proxy accedendo da web a /proxy-sample.php oppure /proxy-login.php

Requisiti

Installazione

Clonare, oppure salvare i file di spid-php, in una directory non esposta sul web (__NON salvare i file del progetto nella root o in una sottodirectory del server web come www o public_html__). Quindi lanciare il comando di installazione dalla directory principale di spid-php.

# composer install

Al termine dell'installazione tutte le configurazioni sono salvate nei file spid-php-setup.json, spid-php-openssl.cnf e spid-php-proxy.json. In caso di reinstallazione, le informazioni di configurazione saranno recuperate automaticamente da tali file, senza la necessità di doverle reinserire nuovamente.

Disinstallazione

# composer uninstall

La disinstallazione non cancella gli eventuali file spid-php-setup.json, spid-php-openssl.cnf e spid-php-proxy.json locali che contengono le configurazioni inserite durante il processo in installazione.

Aggiornamento Metadata IdP

# composer update-metadata

Aggiornamento Certificati

# composer make-certificate <days>

Il parametro <days> indica il numero di giorni di validità del certificato; se omesso, il valore predefinito è 730 giorni.

Firma metadata

# composer sign-metadata <metadata.xml> <metadata-signed.xml>

Il parametro <metadata.xml> indica il nome del file xml del metadata da firmare; se omesso, il valore predefinito è metadata.xml.
Il parametro <metadata-signed.xml> indica il nome del file xml del metadata firmato; se omesso, il valore predefinito è metadata-signed.xml.

Reinstallazione / Aggiornamento

# composer uninstall
# composer install

Se nella directory locale sono presenti i file spid-php-setup.json e spid-php-openssl.cnf, l'aggiornamento non richiederà nuovamente le informazioni di configurazione. Per modificare le informazioni di configurazione precedentemente inserite, occorrerà eseguire la disinstallazione, cancellare o modificare manualmente il file spid-php-setup.json, quindi procedere alla nuova installazione. Per rigenerare i certificati occorrerà eseguire la disinstallazione, rinominare o cancellare la directory /cert o i certificati spid-sp.crt e spid-sp.pem in essa presenti, quindi procedere ad una nuova installazione.

Configurazione nginx

Per utilizzare SimpleSAMLphp su webserver nginx occorre configurare nginx come nell'esempio seguente. In myservice inserire il nome del servizio come specificato durante l'installazione.

Prerequisiti per certificati self-signed

Per fare valido l'uso del snippets/snakeoil.conf file su Nginx, è necessario generare il certificato "self-signed" /etc/ssl/certs/ssl-cert-snakeoil.pem attraverso la installazione del package ssl-cert su distribuizioni Debian based (come Ubuntu), con il comando:

sudo apt-get install ssl-cert

O, in alternativa, generare il certificato manualmente tramite OpenSSL, con il comando:

sudo make-ssl-cert generate-default-snakeoil --force-overwrite

Configurazione

server {  
  listen 443 ssl http2;  
  server_name sp.example.com;
  root /var/www;
  include snippets/snakeoil.conf;  

  location / {
    try_files $uri $uri/ =404;
    index index.php;
    location ~ \.php$ {
      include snippets/fastcgi-php.conf;  
      fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }
  }

  location /myservice/ {
    alias /var/www/spid-cie-php/vendor/simplesamlphp/simplesamlphp/www/;
    index index.php;
    location ~ ^(?<prefix>/myservice)(?<phpfile>.+?\.php)(?<pathinfo>/.*)?$ {
      fastcgi_param SCRIPT_FILENAME $document_root$phpfile;
      fastcgi_param PATH_INFO $pathinfo if_not_empty;
      fastcgi_pass unix:/run/php/php8.1-fpm.sock;
      include fastcgi_params;
    }
  }
}

Metadata

Dopo aver completato la procedura di installazione è possibile scaricare i metadati alle seguenti url:

Metadata SPID

/myservice/module.php/saml/sp/metadata.php/spid

dove myservice è il nome del servizio come specificato durante l'installazione.

Metadata CIE

/myservice/module.php/saml/sp/metadata.php/cie

dove myservice è il nome del servizio come specificato durante l'installazione.

API SDK

Costruttore

new SPID_PHP()

isSPIDEnabled

bool isSPIDEnabled()

restituisce true se è stata eseguita le configurazione per SPID, false altrimenti

isCIEEnabled

bool isCIEEnabled()

restituisce true se è stata eseguita le configurazione per CIE, false altrimenti

isAuthenticated

bool isAuthenticated()

restituisce true se l'utente è autenticato, false altrimenti

isIdPAvailable

bool isIdPAvailable($idp)

restituisce true se il valore di $idp è tra quelli previsti (vedi login)

isIdP

bool isIdP($idp)

restituisce true se l'utente è autenticato con l'idp $idp (vedi login)

requireAuth

void requireAuth()

richiede che l'utente sia autenticato. Se l'utente non è autenticato mostra il pannello di scelta dell'IDP

insertSPIDButtonCSS

void insertSPIDButtonCSS()

inserisce i riferimenti css necessari per la presentazione del bottone

insertSPIDButtonJS

void insertSPIDButtonJS()

inserisce i riferimenti al codice javascript necessario al funzionamento del bottone

insertSPIDButton

void insertSPIDButton($size, [$method='GET'])

stampa il codice per l'inserimento del pulsante 'Entra con SPID'.

$size specifica la dimensione del pulsante (S|M|L|XL)

$method specifica la versione del pulsante (GET|POST)

insertCIEButton

void insertCIEButton([$size='default'])

stampa il codice per l'inserimento del pulsante 'Entra con CIE'.

$size specifica la dimensione del pulsante (default)

setPurpose (solo per SPID)

void setPurpose($purpose)

imposta l'estensione "Purpose" nell'AuthenticationRequest per inviare una richiesta di autenticazione per identità digitale ad uso professionale (Avviso SPID n.18 v.2). $purpose specifica il valore dell'estensione Purpose (P|LP|PG|PF|PX)

login

void login($idp, $level, [$returnTo], [$attributeConsumingServiceIndex], [$post])

invia una richiesta di login livello $level verso l'idp $idp. Dopo l'autenticazione, l'utente è reindirizzato alla url eventualmente specificata in $returnTo. Se il parametro $returnTo non è specificato, l'utente è reindirizzato alla pagina di provenienza.

$idp può assumere uno dei seguenti valori:

$level può assumere uno dei seguenti valori

$post può assumere valore

Se $post è true specifica che la AuthnRequest deve essere inviata in Binding HTTP-Post invece che HTTP-Request (default)

getResponseID

string getResponseID()

restituisce l'attributo ID della SAML Response ricevuta dall'IdP

getAttributes

array getAttributes()

restituisce gli attributi dell'utente autenticato

getAttribute

string getAttribute(string $attribute)

restituisce il valore per lo specifico attributo

logout

void logout([$returnTo])

esegue la disconnessione. Dopo la disconnessione, l'utente è reindirizzato alla url specificata in $returnTo oppure alla pagina di provenienza se $returnTo non è specificato.

getLogoutURL

string getLogoutURL([$returnTo])

restituisce la url per eseguire la disconnessione. Dopo la disconnessione, l'utente è reindirizzato alla url specificata in $returnTo oppure alla pagina di provenienza se $returnTo non è specificato.

Esempio di integrazione

require_once("<path to spid-php>/spid-php.php");

$spidsdk = new SPID_PHP();

if(!$spidsdk->isAuthenticated()) {
    if(!isset($_GET['idp'])) {
        $spidsdk->insertSPIDButtonCSS();
        $spidsdk->insertSPIDButton("L");       
        $spidsdk->insertSPIDButtonJS();         
    } else {
        $spidsdk->login($_GET['idp'], 1);                
    }
} else {
    foreach($spidsdk->getAttributes() as $attribute=>$value) {
        echo "<p>" . $attribute . ": <b>" . $value[0] . "</b></p>";
    }

    echo "<hr/><p><a href='" . $spidsdk->getLogoutURL() . "'>Logout</a></p>";
}

Utilizzo come Proxy

Durante l'installazione è possibile scegliere se installare i file di esempio per l'utilizzo di spid-php come proxy.

In tal caso viene richiesto:

Se si seleziona Y alla domanda se firmare la response, i dati dell'utente saranno inviati alla URL di redirect in POST contenuti in un token in formato JWS firmato con la chiave privata del certificato del Service Provider generato durante l'installazione e salvato in /cert.

Se non si seleziona Y alla domanda se firmare la response, i dati dell'utente saranno inviati, invece, alla URL di redirect in POST come variabili in chiaro.

Se oltre alla firma, si seleziona Y anche alla domanda se cifrare la response, questa sarà inviata alla URL di redirect in POST come token in formato JWS il cui payload contiene nell'attributo data un token JWE cifrato con un client_secret contenente i dati dell'utente.

client_id e client_secret sono generati automaticamente per il client durante il setup, mostrati a video e salvati nel file spid-php-proxy.json.

Per inserire ulteriori client con le relative configurazioni di client_id, client_secret e redirect_uri, è possibile editare il file spid-php-proxy.json

API Proxy

login

GET /proxy.php?action=login&client_id=<client_id>&redirect_uri=<redirect_uri>&idp=<idp>&state=<state>

Invia la AuthnRequest ad uno specifico IdP e ritorna la Response decodificata o come JWS o JWS(JWE) in POST alla redirect_uri del client.

Parametri:

logout

GET /proxy.php?action=logout&client_id=<client_id>

Esegue la disconnessione dall'IdP.

Parametri:

verify

GET /proxy.php?action=verify&token=<token>&decrypt=<decrypt>&secret=<secret>

Verifica e decifra il token JWT ricevuto con la response.

Parametri:

Nel caso in cui non è possibile verificare la firma oppure non è possibile decifrare la response (perchè il secret non è corretto oppure perchè il token è malformato) viene restituito status code 422.

Si consiglia di utilizzare l'endpoint verify esclusivamente per la verifica della firma dei messaggi. Per decifrare i dati dell'utente, invece, si consiglia di implementare la decodifica sul client.

Esempio di utilizzo del proxy

<a href="https://github.com/italia/spid-cie-php/blob/master/proxy-login.php">Go to Login Page or...</a><br/>
<a href="https://github.com/italia/spid-cie-php/blob/master/proxy.php?client_id=<client_id>&action=login&redirect_uri=/proxy-sample.php&idp=DEMOVALIDATOR&state=state">Login with a single IdP (example for DEMO Validator)</a>
<p>
    <?php
        foreach($_POST as $attribute=>$value) {
            echo "<p>" . $attribute . ": <b>" . $value . "</b></p>";
        }
    ?>
</p>
<a href="https://github.com/italia/spid-cie-php/blob/master/proxy-spid.php?client_id=61504487f292e&action=logout">Esci</a>

Gestione degli errori SPID

Durante il processo di autenticazione SPID posso verificarsi degli errori che vengono generati dagli IDP, determinati dall'interazione dell'utente con la form di login oppure da formati delle richieste che non rispettano le regole tecniche di SPID.

La tabella con i messaggi di errore è disponible qui

Lo script /error.php viene richiamato alla ricezione di un messaggio di Response che contiene i dettagli dell'errore.

Author

Michele D'Amico (damikael)

Credits

Linfa Service ManyDesigns

Contributors

SPID Compliance


_Compliance with SPID regulations (for Service Providers)_
status notes
SPID Avviso n.18 v.2:
SPID Avviso n.29 v.3:
generation of certificates
generation of metadata
Metadata:
parsing of IdP XML metadata (1.2.2.4)
parsing of AA XML metadata (2.2.4)
SP XML metadata generation (1.3.2)
AuthnRequest generation (1.2.2.1):
generation of AuthnRequest XML
HTTP-Redirect binding
HTTP-POST binding
AssertionConsumerServiceURL customization
AssertionConsumerServiceIndex customization
AttributeConsumingServiceIndex customization
AuthnContextClassRef (SPID level) customization
RequestedAuthnContext/@Comparison customization
RelayState customization (1.2.2)
Response/Assertion parsing
verification of Response/Signature value (if any)
verification of Response/Signature certificate (if any) against IdP/AA metadata
verification of Assertion/Signature value
verification of Assertion/Signature certificate against IdP/AA metadata
verification of SubjectConfirmationData/@Recipient
verification of SubjectConfirmationData/@NotOnOrAfter
verification of SubjectConfirmationData/@InResponseTo
verification of Issuer
verification of Destination
verification of Conditions/@NotBefore
verification of Conditions/@NotOnOrAfter
verification of Audience
parsing of Response with no Assertion (authentication/query failure)
parsing of failure StatusCode (Requester/Responder)
verification of RelayState (saml-bindings-2.0-os 3.5.3)
Response/Assertion parsing for SSO (1.2.1, 1.2.2.2, 1.3.1):
parsing of NameID
parsing of AuthnContextClassRef (SPID level)
parsing of attributes
Response/Assertion parsing for attribute query (2.2.2.2, 2.3.1):
parsing of attributes
LogoutRequest generation (for SP-initiated logout):
generation of LogoutRequest XML
HTTP-Redirect binding
HTTP-POST binding
LogoutResponse parsing (for SP-initiated logout):
parsing of LogoutResponse XML
verification of LogoutResponse/Signature value (if any)
verification of LogoutResponse/Signature certificate (if any) against IdP metadata
verification of Issuer
verification of Destination
PartialLogout detection
LogoutRequest parsing (for third-party-initiated logout):
parsing of LogoutRequest XML
verification of LogoutRequest/Signature value (if any)
verification of LogoutRequest/Signature certificate (if any) against IdP metadata
verification of Issuer
verification of Destination
parsing of NameID
LogoutResponse generation (for third-party-initiated logout):
generation of LogoutResponse XML
HTTP-Redirect binding
HTTP-POST binding
PartialLogout customization
AttributeQuery generation (2.2.2.1):
generation of AttributeQuery XML
SOAP binding (client)