Con una Web App un sistema esterno può richiedere l’accesso a Space specifici tramite l’API del servizio web. L’utente può concedere l’accesso ad altri sistemi in modo automatizzato. Il flusso OAuth 2.0 descrive questo concetto in dettaglio.
In generale, la specifica OAuth lascia un certo margine per adattamenti a questo caso d’uso concreto.
L’integrazione segue in linea di massima la specifica OAuth. Al flusso partecipano i seguenti attori:
Utente: L’utente può concedere alla Web App l’accesso a uno Space. L’utente è di solito l’esercente che concede l’accesso alla vostra applicazione.
Client: Il client richiama l’API del servizio web per accedere ai dati all’interno dello Space. Questa è la vostra applicazione. La vostra applicazione può anche essere eseguita su un server web.
Server: In questa documentazione usiamo il termine server per il nostro sistema. Come nel modello client-server, il nostro sistema rappresenta il server.
Per mantenere semplice questa documentazione riutilizziamo la terminologia della specifica OAuth.
La figura sopra mostra i seguenti passaggi:
L’utente richiede l’installazione della Web App.
La Web App (client) restituisce l’URL di autorizzazione tramite il quale l’utente concede l’accesso alla Web App.
L’URL di autorizzazione richiede che sia presente una redirect_uri.
Quando l’utente richiama l’URL di autorizzazione, il server a sua volta chiede all’utente di confermare
l’autorizzazione richiesta sullo Space. Come risultato, il server restituisce la
redirect_uri al browser.
Il browser richiama la redirect_uri che punta a un URL
controllato dalla Web App. La redirect_uri contiene un parametro code con cui
la Web App può richiedere l’installazione dell’applicazione.
Le sezioni seguenti trattano i passaggi sopra indicati in maggiore dettaglio.
Come primo passaggio dovete configurare una Web App e recuperare il client_id e il client_secret.
Ci sono due modi in cui l’utente può avviare l’installazione. In entrambi i casi la Web App deve inoltrare l’utente all'`authorization URL`. Vedi Richiedere l’autorizzazione su come farlo.
Opzione 1: L’utente attiva l’installazione dall’interno della nostra applicazione. In questo caso inoltriamo l’utente all'`Installation Redirect URL` come definito nella configurazione della Web App. In questo caso l’utente richiamerà l'`Installation Redirect URL` come richiesta HTTP GET. Ci assicuriamo che la richiesta contenga i seguenti parametri:
space_id: L’applicazione viene installata nello Space risolto dall’ID dello Space.
action: L’azione è impostata su install. L’azione permette di capire quale operazione deve essere eseguita.
timestamp: Il timestamp in secondi dal 1970. Questo permette di verificare gli attacchi di tipo replay. Si raccomanda di rifiutare le richieste più vecchie di alcune ore.
hmac: Un HMAC viene calcolato in base ai parametri di richiesta space_id, action e timestamp. Questo permette la
verifica che una richiesta provenga realmente da noi. Vedi Calcolo dell’HMAC.
Opzione 2: L’utente attiva l’installazione dall’interno della Web App. In questo caso la Web App deve richiedere l’ID dello Space o usare un altro approccio per recuperarlo.
Per richiedere l’autorizzazione all’utente, l’utente deve essere inoltrato a: https://gateway.vr-payment.de/oauth/authorize
La richiesta deve contenere i seguenti parametri di richiesta:
space_id: L’applicazione viene installata nello Space risolto dall’ID dello Space.
redirect_uri: L’URI a cui l’utente viene reindirizzato dopo che ha autorizzato l’accesso. La
configurazione della Web App deve contenere questo URL come redirection endpoint, altrimenti verrà rifiutato.
scope: Il parametro scope contiene un elenco, separato da spazi, degli ID di autorizzazione richiesti. La lista delle autorizzazioni fornisce l’elenco completo di tutte le autorizzazioni che possono essere richieste.
state: Un valore generato casualmente, fornito dalla vostra applicazione (client), che è univoco per ogni
richiesta di autorizzazione. Quando l’utente torna alla redirect_uri includiamo nuovamente questo valore. È importante che
verifichiate questo valore, poiché la sicurezza può essere compromessa. Raccomandiamo di assicurarvi che lo state non possa essere usato per
attacchi di tipo replay (ad es. includere un timestamp e rifiutare le richieste troppo vecchie).
client_id: L’ID client che identifica la vostra applicazione. Il client ID può essere recuperato nella configurazione della Web App.
Se nel parametro scope richiedete autorizzazioni che necessitano di funzionalità specifiche non disponibili per lo Space,
proviamo o ad attivare quelle funzionalità oppure a restituire un insieme ridotto di autorizzazioni alla conferma dell’installazione.
Rimuoviamo quindi le autorizzazioni che non possiamo concedere.
Esempio di richiesta:
https://gateway.vr-payment.de/oauth/v2/authorize?space_id=15023&client_id=14141&redirect_uri=https%3A%2F%2Fexample.com%2Fconfirm%2Finstall&state=1609445756&scope=1432736711150%201432736711152
|
Note
|
Nel caso in cui vogliate modificare le autorizzazioni della Web App a un certo punto, potete eseguire gli stessi passaggi come se installaste
l’applicazione da zero. Potete inoltrare l’utente all'`\https://gateway.vr-payment.de/oauth/v2/authorize` con il parametro scope adattato. Tutti i passaggi seguenti rimangono uguali.
|
Quando l’utente torna alla redirect_uri, la Web App deve confermare l’installazione e recuperare
l'`access_token` in conformità con la specifica OAuth.
Insieme alla redirect_uri verranno inviati i seguenti parametri:
state: Il parametro state contiene il valore trasmesso all’URL di autorizzazione. Verificate che questo valore sia identico al valore che avete trasmesso.
space_id: L’ID dello Space a cui l’utente ha concesso l’accesso.
timestamp: Il momento in cui l’utente ha concesso l’accesso. L’orario è in secondi dal 1970 (timestamp Unix). Verificate che la concessione non sia troppo vecchia. Un valore ragionevole qui è di circa 10 minuti. Questo previene gli attacchi di tipo replay.
code: Il codice identifica la concessione creata nel passaggio precedente. Avete bisogno di questo codice per confermare l’installazione. Vedi sotto come farlo.
return_url: L’URL a cui l’utente può essere reindirizzato dopo il completamento dell’installazione. Il parametro opzionale message può essere aggiunto
all’URL per visualizzare un messaggio personalizzato. Il parametro URL type definisce se viene visualizzato un messaggio success o un messaggio failure.
hmac: L’HMAC permette di verificare che la richiesta non sia stata manomessa. Vedi Calcolo dell’HMAC su come potete farlo.
Esempio di richiesta:
https://example.com/confirm/install?state=1609445756&space_id=14141×tamp=1609449756&code=AdF7812311414312312387483&hmac=8jAYtV4R7FFTjl3UqWpkmBy78PVQdDygJ1NbM7v_-1AcAMWMhv45PPJA-nYkNT4gCNZ2XECYF3-N5W29ZXGJ6Q
Per confermare l’installazione dovete inviare una chiamata API. Dovete inviare un messaggio POST all'
URL https://gateway.vr-payment.de/api/v2.0/web-apps/confirm/{code}. Vedi anche la documentazione del servizio web.
Poiché questo è un normale endpoint del servizio web, dovete fornire le credenziali di autenticazione nell’header della richiesta HTTP.
A questo scopo usate il client_id come ID utente e per il client_secret il secret.
La risposta è simile al seguente esempio:
{
"access_token": "dummy-value",
"scope": "1432736711150 1432736711152",
"space": 14141,
"state": "1609445756",
"token_type": "web-service-hmac",
}
In questo passaggio dovreste verificare se la lista scope restituita corrisponde a quanto avete richiesto e se l’insieme restituito
soddisfa i vostri requisiti. Come indicato in precedenza, non in tutte le situazioni possono essere concesse tutte le autorizzazioni richieste.
Il passaggio successivo tratta come richiamare effettivamente l’API del servizio web.
Una volta che l’applicazione è stata installata con successo nello Space, il client_id e il client_secret possono essere usati per accedere all’API del servizio web
per il determinato Space. Sull’API del servizio web dovete usare il client_id come ID utente e il client_secret come secret.
La chiamata dell’API avviene nello stesso modo in cui creereste un utente applicativo e usereste le sue credenziali per richiamare l’API.
L’URL di reindirizzamento della configurazione permette di definire una pagina su cui la Web App può essere configurata dall’utente. Ciò significa che l’elenco delle Web App
conterrà un pulsante Configure che reindirizza l’utente all’URL definito nella configurazione della Web App.
L’URL di reindirizzamento contiene i seguenti parametri:
space_id: L’ID dello Space identifica lo Space per cui la configurazione deve essere adeguata.
timestamp: Il timestamp in secondi dal 1970. Questo permette di verificare gli attacchi di tipo replay. Si raccomanda di rifiutare le richieste più vecchie di alcune ore.
action: L’azione è impostata su configure. L’azione vi permette di capire l’azione attivata dall’utente.
return_url: L’URL a cui l’utente può essere reindirizzato dopo il completamento della configurazione. Il parametro opzionale message può essere aggiunto all’URL. Questo messaggio verrà visualizzato all’utente. Il parametro type definisce se viene visualizzato un messaggio success o un messaggio failure.
hmac: Un HMAC viene calcolato in base ai parametri di richiesta space_id, action, return_url e timestamp. Questo permette la
verifica che una richiesta provenga realmente da noi. Vedi Calcolo dell’HMAC.
|
Note
|
Dovreste sempre verificare l'`hmac` per evitare che un utente malintenzionato possa modificare la configurazione di un’applicazione. L'`hmac` garantisce che l’utente sia autorizzato a eseguire l’operazione di configurazione. |
Per mantenere la vostra Web App sincronizzata con lo stato di installazione all’interno dei diversi Space, raccomandiamo di configurare un URL di notifica. Qualsiasi modifica all’installazione della Web App all’interno di uno Space verrà segnalata su tale URL.
Inviamo un messaggio HTTP POST con il seguente corpo:
{
"space_id": 15023,
"client_id": "14141",
}
Se l’applicazione sia stata installata o disinstallata non fa parte del messaggio. Usate l’API del servizio web per scoprire quale sia stato il fattore scatenante per cui abbiamo inviato questo messaggio.
Il comportamento sopra descritto è intenzionale. Risolve i seguenti problemi:
Può accadere che una notifica venga inviata con un ritardo perché abbiamo avuto difficoltà a raggiungere il vostro sistema. In tal caso leggete comunque lo stato di installazione da un’unica fonte che detiene lo stato corretto.
Non ci sono rischi di sicurezza poiché nessuna informazione critica è inclusa nella richiesta HTTP. Il messaggio è solo un fattore scatenante affinché recuperiate le informazioni corrette tramite l’API del servizio web.
In alcuni casi la Web App e il nostro sistema potrebbero non essere più sincronizzati a causa di interruzioni temporanee. Con l’approccio sopra descritto potete decidere di recuperare lo stato di installazione attuale in qualsiasi momento.
|
Note
|
Tenete presente che un’interruzione del vostro sistema potrebbe impedirci di inviare notifiche al vostro sistema. In tal caso inviamo un' e-mail se specificato nella configurazione della vostra Web App. |
Per verificare che le richieste provengano dal nostro sistema aggiungiamo un HMAC con SHA-512. Esso garantisce
che i parametri non vengano modificati durante la trasmissione. Questo è simile a un normale hash ma in modo sicuro.
La maggior parte dei linguaggi di programmazione fornisce un’implementazione per il calcolo dell'`HMAC`.
In generale dobbiamo prima costruire una stringa e proteggerla in seguito con il client_secret. A tal fine
prendiamo tutti i parametri, li ordiniamo alfabeticamente e li concateniamo con un | (barra verticale).
Vedi il seguente esempio PHP con i parametri: space_id, timestamp, client_id e scope
<?php
$client_secret = "OWOMg2gnaSx1nukAM6SN2vxedfY1yLPONvcTKbhDv7I=";
$requestParameters = array();
$requestParameters['client_id'] = "14141";
$requestParameters['state'] = "87ggfr456zghjui876tgvbji";
$requestParameters['space_id'] = 15023;
$requestParameters['scope'] = "1432736711150 1432736711152";
// We sort the array elements by the element's key
ksort($requestParameters);
$parametersToSecure = array();
foreach ($requestParameters as $key => $value) {
$parametersToSecure[] = $key . "=" . $value;
}
$toSecure = implode('|', $parametersToSecure);
$decodedSecret = base64_decode($client_secret);
$hmacValue = base64_encode(hash_hmac("sha512", $toSecure, $decodedSecret, true));
// Replacing "+" with "-" and "/" with "_"
$cleanedMac = $url = strtr($hmacValue, '+/', '-_');
// Remove padding
$cleanedMac = rtrim($cleanedMac, '=');
echo $cleanedMac;
Note:
Non codifichiamo in URL i parametri quando calcoliamo l’HMAC. Quando la vostra infrastruttura (ad es. il server) non decodifica automaticamente il parametro URL, potreste doverlo fare prima di calcolare l’HMAC.
Il client_secret fornito nella pagina di configurazione della Web App è codificato come stringa Base64. Dobbiamo prima convertirlo in binario.
I parametri da proteggere dipendono dal caso d’uso. Usiamo l’HMAC in diverse situazioni, quindi adattate i parametri di conseguenza. Includiamo solo i parametri esplicitamente elencati. Non includiamo mai tutti i parametri. Quindi se la richiesta contiene ulteriori parametri, ignorateli.
L’HMAC incluso nella richiesta è sempre codificato in Base64. Quando confrontate l’HMAC calcolato con l’HMAC trasmesso, confrontateli nel formato binario oppure assicuratevi di unificare prima i diversi formati Base64. A causa del fatto che trasmettiamo l’HMAC come parametro URL, dobbiamo usare un’implementazione compatibile con gli URL senza riempimento. Vedi RFC 4648
I valori dei parametri potrebbero provenire da un oggetto JSON. In tal caso i valori devono essere convertiti in stringhe prima di concatenarli.
I numeri in virgola mobile sono rappresentati con un punto e con lo stesso numero di cifre presenti nel JSON e verranno aggiunti anche eventuali zeri opzionali alla fine. I booleani devono essere rappresentati come true o false.
In alcuni casi gli endpoint della vostra applicazione verranno richiamati da una richiesta HTTP inviata tramite i nostri server ai vostri server. La richiesta avviene quindi senza l' utente (browser). Questa sezione tratta informazioni importanti su queste chiamate.
In alcuni casi dobbiamo informarvi di determinate attività che la vostra applicazione deve svolgere. In quei casi usiamo chiamate remote. Quelle chiamate inviano a un URL definito da voi una richiesta HTTP con alcuni dati. I dati che inviamo dipendono dal caso d’uso concreto. Qui trattiamo solo gli aspetti che si applicano a tutti i tipi di chiamate.
Usate quindi le documentazioni corrispondenti per i casi d’uso concreti per capire cosa conterrà l’effettivo corpo della richiesta.
Ogni richiesta contiene un header x-mac-value. Questo header contiene un HMAC che vi permette di verificare che la richiesta provenga realmente dai nostri
sistemi. Inoltre la richiesta contiene anche l’header x-timestamp che indica il momento in cui la richiesta è stata creata. Il timestamp contiene l’orario in secondi dal primo gennaio
1970. Si tratta quindi di un timestamp Unix.
Per verificare l’HMAC dovete concatenare il valore di x-timestamp con una barra verticale (|) e il corpo della richiesta. La stringa risultante dovete trasmetterla all’HMAC con l’algoritmo SHA-512.
Come secret potete usare il secret generato per l’applicazione. Quindi lo stesso secret che usate anche per richiamare la nostra API del servizio web.
Vedi sotto anche un esempio in PHP:
<?php
$client_secret = "OWOMg2gnaSx1nukAM6SN2vxedfY1yLPONvcTKbhDv7I=";
$hmac = $_SERVER['HTTP_X_MAC_VALUE']; // PHP requires to transform the header name.
$timestamp = $_SERVER['HTTP_X_TIMESTAMP']; // PHP requires to transform the header name.
$body = file_get_contents('php://input'); // That might be different depending on how you run PHP
$toSecure = $timestamp . '|' . $body;
$decodedSecret = base64_decode($client_secret);
$calculatedHmac = base64_encode(hash_hmac("sha512", $toSecure, $decodedSecret, true));
if (strtolower($calculatedHmac) !== strtolower($hmac)) {
die('The calculated HMAC does not match with the supplied one.');
}
$allowedOffset = 15 * 60; // 15 minutes
if ($timestamp < time() - $allowedOffset) {
die('The request has expired. This seems like a reply attack.');
}
Nel caso in cui il vostro server sia offline ripetiamo le richieste più volte. Consideriamo la richiesta consegnata con successo quando riceviamo una risposta HTTP con un codice di stato HTTP 2XX. Qualsiasi altra risposta verrà considerata come fallita. Ciò include i reindirizzamenti tramite il codice di stato HTTP 302 o 301.
Anche quando il server non è raggiungibile ripeteremo la chiamata. C’è inoltre un timeout di 30 secondi. Il vostro server deve rispondere entro 30 secondi, altrimenti ripetiamo
la chiamata. Quando ripetiamo la chiamata includiamo header aggiornati (x-mac-value e x-timestamp) e potenzialmente anche il corpo potrebbe contenere dati aggiornati.
Sta a voi decidere come gestire le chiamate multiple. A seconda del caso d’uso ci sono diverse alternative. Controllate la documentazione corrispondente per vedere quali possibilità avete per impedire l’esecuzione dell’operazione corrispondente più di una volta.