MeCloud
Brings me to the cloud!
Introduzione
MeCloud
è un'architettura Cloud SaaS (Software as a Service) che permette agli utenti
di effettuare l'upload di documenti testuali nei formati txt, rtf e htm,
permette di leggere ed editarli direttamente “online” ed inoltre permette di
effettuare l'upload di immagini, di visualizzare le immagini caricate e di
condividere con altri utenti di MeCloud le immagini e i documenti caricati.
Il
servizio è totalmente gratuito e prevede altre features come la cerazione e la
gestione di nuove applicazioni e l'inserimento di inserzioni pubblicitarie e
script per il SEO (Search Engine Optimization) però queste funzioni (seppur
previste nel Web Service) non sono state realizzate nel sito di testing come
caso di studio per l'esame di Web.
Architettura
per l'implementazione reale (business):
Questa
soluzione prevede un server contenente apache e il sito in php, N server
(virtuali) in cloud sparsi per il mondo ospitanti ognuno un Web Service MeCloud
e X server SQL in replica tra loro (tutti contengono gli stessi dati) con X
<< N .
Il
database di MeCloud prevede una soluzione che permette di gestire utenti
diversi su diversi Web Service e addirittura documenti (file degli utenti)
diversi su Web Services diversi.
Cioè se
l'utente n1 effettua l'upload del file “xyz” tale file sarà caricato su un
WebService scelto mediante una politica di random o performance. Così più file
di ogni utente vengono caricati su diversi WebServices sparsi per il globo terrestre
(the cloud).
Inoltre
se altri utenti sono abilitati ad accedere a tali file, perché esplicitamente
condivisi, questi potranno accederci senza problemi usando tutti i diversi Web
Services necessari, tutto questo a totale insaputa dell'utente finale. In questo modo si realizza la relazione molti
a molti (un grafo) tipica di un social network.... però di files e applicazioni
online!
Questa
architettura viene chiamata “Cloud Balancing” e solo poche aziende al mondo
la possiedono (Google App Engine, Amazon EC2).
MeCloud
Web Service
Il Web
Service di MeCloud si divide in 2 sotto servizi:
- Web Service SOAP per l'autenticazione e
l'interscambio di informazioni da e verso il sito o un'applicazione
esterna.
- Web Service HTTP Request per la creazione di path
virtuali verso i file e lo streaming del contenuto dei file attraverso
HTTP.
Per
evitare di dare l'accesso diretto (la full path) del file presente sul server
al client, il Web Service, mediante il secondo sotto servizio, ad ogni
richiesta crea una path virtuale verso il file e lo trasferisce al client
mediante http. Tale path virtuale è data dal passaggio di parametri queli l'ID
del file richiesto e il TokenID (cifrato con RSA a 1024 bit e codificato in
base64) della sessione.
Per
maggiori informazioni riguardo il sistema di cifratura usato fare riferimento
alla sezione Sicurezza in MeCloud del presente documento.
La path
virtuale verso un documento (o immagine) quindi sarà così modellata:
http://mecloud.us:8081/file?id=”idDelFile”&tk=”idCifratoEcodificatoDellaSessione”
Il
parametro tk è il TokenID della sessione: ogni utente dopo aver effettuato il
login ha un tokenid, tale stringa di 32 caratteri rappresenta l'utente
all'interno del sistema. La stringa viene rigenerata a random ad ogni login ed
è diversa per ogni utente.
Ho
implementato un algoritmo di “collision prevent” per la generazione automatica
di stringhe a 32 caratteri (vedere
funzione RandomString di MeCloudService.asmx.cs).
Il web
service soap MeCloudService utilizza il protocollo di comunicazione SOAP
(Simple Object Access Protocol) versione 1.1 e 1.2 che si attiene alle
specifiche REST dove:
Lo
stato dell'applicazione e le funzionalità sono divisi in Risorse WEB
§ Ogni risorsa è unica e
indirizzabile usando sintassi universale per uso nei link ipertestuali
§ Tutte le risorse sono condivise
come interfaccia uniforme per il trasferimento di stato tra client e risorse,
questo consiste in:
§ un insieme vincolato di
operazioni ben definite
§ un insieme vincolato di
contenuti, opzionalmente supportato da codice on demand
§ un protocollo che è:
§ Client-Server
§ Stateless
§ Cachable
§ A livelli
Il Web
Service nonostante sia implementato in C# .NET gira su Linux Ubuntu 11.04
grazie al framework open source Mono che ne garantisce anche la portabilità su
piattaforme Windows e Unix Like a 32 o 64 bit senza bisogno di ricompilare il
tutto per la specifica architettura.
Lista
dei metodi implementati in MeCloudService Web Service:
Operation / Method Name
|
SOAPAction*
|
Input Message
|
Output Message
|
Login
|
http://mecloud.us/Login
|
||
LostPassword
|
http://mecloud.us/LostPassword
|
||
ShareItem
|
http://mecloud.us/ShareItem
|
||
SendInvitations
|
http://mecloud.us/SendInvitations
|
||
DeleteItem
|
http://mecloud.us/DeleteItem
|
||
GetLinearizedListOfItems
|
http://mecloud.us/GetLinearizedListOfItems
|
||
Register
|
http://mecloud.us/Register
|
||
UploadFile
|
http://mecloud.us/UploadFile
|
||
AddApp
|
http://mecloud.us/AddApp
|
||
ShareApp
|
http://mecloud.us/ShareApp
|
||
RemoveAppAssociation
|
http://mecloud.us/RemoveAppAssociation
|
||
GetAppList
|
http://mecloud.us/GetAppList
|
||
StoreSettings
|
http://mecloud.us/StoreSettings
|
||
GetSettings
|
http://mecloud.us/GetSettings
|
||
GetUserInfo
|
http://mecloud.us/GetUserInfo
|
- Il Metodo
Login
: Il Metodo di Login accetta 3
parametri in input:
Input Parameters
encryptedBase64Mail
|
string
|
encryptedBas64Password
|
string
|
encryptedBase64APIKey
|
string
|
Output Parameters
LoginResult
|
string
|
Tale
metodo permette di autenticarsi nel sistema MeCloud.
Il
sito invia i parametri (mail, password e API Key) cifrati con la chiave pubblica
del sistema e codificati in base64. Il WS dopo aver decodificato da base64 a
UTF-8 la stringa e dopo aver decriptato la stessa, effettua una query sul db
per vedere se la API Key è presente, se il risultato è affermativo allora la
procedura continua, altrimenti il WS ritorna un errore di “bad API Key”.
Dopodiché si verifica la presenza della mail nel db e in caso affermativo si
estrae la password e la si confronta con la password passata in input dal sito.
Le password sono “case sensitive”. Se le password coincidono, il WS ritornerà
in output il TokenID (generato automaticamente in questo istante e che ha la
durata dell’intera sessione per poi essere rigenerato) della sessione ma non
cifrato, in caso contrario un errore di “bad password”.
- Il Metodo
LostPassword:
Accetta in input un solo parametro:
Input
Parameters
encryptedBase64Mail
|
string
|
Questo
metodo server a rinviare la password in caso di smarrimento.
Se
la Mail cifrata e codificata è presente nel database, allora verrà estratta la
relativa password e quest’ultima verrà inviata mediante una mail alla mailbox
relativa. Se la password non è presente, nulla verrà inviato. Il metodo non
restituisce alcun parametro (void).
- Il Metodo
ShareItem:
Accetta 4 parametri in ingresso:
Input
Parameters
base64EncryptedAPIKey
|
string
|
base64EncryptedToken
|
string
|
base64EncryptedOtherUserMail
|
string
|
ItemID
|
string
|
- Output Parameters
ShareItemResult
|
string
|
Questo metodo permette di
condividere un oggetto (immagine o documento) con più utenti.
Il metodo accetta in input 3
parametri cifrati e l’ItemID non cifrato.
Il
sistema dopo aver decriptato e decodificato tutti i parametri in ingresso
controlla la presenza dell’API Key,
estrae l’ID dell’utente (colui che condivide il documento) dal TokenID della
sessione e l’id del secondo utente, colui che subirà la condivisione dal parametro
otherUserMail. Dopodiché associa nella tabella del database USERSTOITEM lo
stesso item a più utenti (nel esempio solo 2), l’utente che ha subìto la
condivisione dell’item riceverà una mail che lo informa dell’avvenuta
condivisione.
- Il Metodo
SendInvitations:
accetta un solo parametro in ingresso, cioè la mail di colui che riceverà
l’invito. Esso serve per inviare inviti ad usare MeCloud a persone non
ancora registrate. Non effettuerà alcun controllo.
- Il Metodo
DeleteItem:
Serve a cancellare un item. Verrà cancellata sia la presenza fisica del
file sul sistema di storage che tutte le referenze relative nel database.
Tale
metodo accetta 3 parametri in input:
Input
Parameters
base64EncryptedAPIKey
|
string
|
base64EncryptedToken
|
string
|
ItemID
|
string
|
Output
Parameters
DeleteItemResult
|
string
|
Dopo
aver decodificato e decriptato i dati in input (tranne ItemID il quale non è
cifrato) viene controllata la presenza dell’API Key nel DB, viene estratto
l’user id relativo al TokenID passato e viene verificata l’esistenza
dell’associazione userid -> itemid nella tabella USERSTOITEM del database.
In caso affermativo, l’eliminazione può avere atto:
viene
cancellato l’item dalla tabella ITEM e dalla tabella USERSTOITEM e dopo viene
cancellato il relativo file fisico dal sistema di storage.
§
Il Metodo
GetLinearizedListOfItems:
ha il compito di ritornare una lista linearizzata contenente gli items di ogni
utente. Tale lista è una stringa dove ogni item diverso è separato dall’altro
item mediante il simbolo “pipe” |. La stringa in output sarà così formattata: FileName1,MimeType1,ServerAddress1,ItemID1|FileName2,MimeType2,ServerAddress2,ItemName2|
Ho
deciso di usare una lista linearizzata perché non è sempre vero che tutti i
linguaggi di programmazione gestiscono array di stringhe serializzate su XML.
Quindi, per compatibilità, ho deciso di linearizzare il tutto. Il quale verrà
poi splittato in array di stringhe da chi invoca il WS.
Input
Parameters
base64EncryptedAPIKey
|
string
|
base64EncryptedToken
|
string
|
Output
Parameters
GetLinearizedListOfItemsResult
|
string
|
§
Il Metodo Register : permette di restrarsi al
sistema
I
parametri sono :
Input Parameters
encryptedBase64Mail
|
string
|
encryptedBas64Password
|
string
|
encryptedBase64RealName
|
string
|
encryptedBase64LastName
|
string
|
Output
Parameters
RegisterResult
|
string
|
I
parametri in input sono 4 però RealName e LastName sono facoltativi, infatti
non vengono usati da MeCloud (sito) in PHP.
Il
sistema restituisce una stringa contenente “ok” se la registrazione ha avuto
successo, altrimenti riporta il tipo di errore (ad esempio “Already
Registered”).
§
Il Metodo UploadFile: permette di caricare file sul
cloud. I file devono avere dimensione inferiore a 25 MBytes e possono essere
soltanto del tipo accettato dal web service, infatti esso controlla il MimeType
del file prima della memorizzazione. I tipi supportati dal WS sono: PDF,
JPG,PNG,GIF,TIFF,MP3,DOC,DOCX,TXT,RTF,PPT,XLS.
Input
Parameters
encryptedBase64Token
|
string
|
encryptedBase64APIKey
|
string
|
data
|
base64Binary
|
encryptedBase64MimeType
|
string
|
encryptedBase64FileNameWithoutPath
|
string
|
Output
Parameters
UploadFileResult
|
string
|
Tutti
i parametri tranne l’array di bytes da trasferire sono codificati e criptati
con RSA.
Una
volta che i dati sono arrivati al WebService mediante SOAP, quest’ultimo
controlla la dimensione dei bytes, i quali devono essere < 25Mbytes. Poi
controlla la correttezza dell’API Key, recupera le informazioni riguardo
l’utente mediante il TokenID, analizza il tipo mime ed è pronto per scrivere il
file sullo storage.
Se
ci sono alcuni problemi durante la scrittura, un’eccezione verrà sollevata e il
file non verrà salvato e la procedura verrà chiusa automaticamente.
Se
il file viene scritto senza problemi, verranno create dei reference all’interno
delle tabelle ITEMS e USERSTOITEM, dove la tabella ITEMS conterrà tutte le
informazioni riguardanti il file caricato, la tabella USERSTOITEM invece
conterrà la relazione itemid -> userid.
§ Il
Metodo GetUserInfo:
è importante per l’integrazione API e l’interazione con altre applicazioni le
quali vogliono recuperare informazioni riguardo l’utente. Per esempio Facebook
o Google mettono a disposizione degli strumenti simili per “tirar fuori”
informazioni riguardo l’utente. In questo caso MeCloud ritorna solo l’user id e
la mail dell’utente. La password non uscirà mai dal sitema, potrà soltanto
essere reinviata alla mail del associata per il recupero della stessa.
Input
Parameters
encryptedBase64Token
|
string
|
encryptedBase64APIKey
|
string
|
Output
Parameters
GetUserInfoResult
|
string
|
§
I Metodi AddApp, ShareApp,
RemoveAppAssociation, GetAppList, StoreSettings, GetSettings sono REALMENTE implementati
all’interno di Mecloud Service WS ma non sono stati implementati nel sito in
php a causa della scarsità di tempo a disposizione.
Tali
metodi permettono agli utenti di memorizzare delle proprie applicazioni (RIA) e
linkarle all’interno del sistema MeCloud, dando l’opportunità all’utente di
creare il proprio contenuto.
Sicurezza
in MeCloud
In un
Web Service di uso pubblico la sicurezza delle informazioni memorizzate è
fondamentale.
Dalla
letteratura informatica si evince che al momento gli algoritmi di cifratura più
sicuri (il che significa non sicuri al 100%) sono gli algoritmi a chiave
pubblica OTP (one time pad).
A causa
dell'overhead causato dal continuo generare di chiavi per ogni richiesta
scambiata tra il sito ed il Web Service (multi-tier architecture), non è
consigliabile usare un sistema (per quanto matematicamente dimostrato come il
più sicuro) one time pad. Per MeCloud ho deciso di cifrare con l'algoritmo
RSA a 1024 bit solo alcune informazioni
scambiate tra il Web Service e il sito in PHP. Per mantenere la compatibilità
tra i due sistemi ho usato uno strumento di generazione chiavi molto conosciuto
ed ultra testato : OpenSSL.
Con
OpenSSL ho generato la chiave pubblica, privata, modulo e il certificato.
Tali
file risiedono sia nella directory “certificates” del sito in php che nella
directory “certificates” del web service MeCloud Service.
Come
precendentemente descritto molti metodi
del web service accettano in ingresso dei parametri cifrati, di solito sono
l'API Key e il Token ID.
Abbiamo
già parlato del TokenID, ma non dell' API Key. Ogni Web Service che si rispetti
ha un APIKey (Google Map, Youtube, Facebook Web Service ed ecc...), questo
ApiKey identifica l'applicazione che sta effettuando la chiamata al web service
e quest'ultimo può applicare delle policy di sicurezza diverse per ogni
applicazione che si interfaccia verso di esso: ad esempio l'API Key di un'applicazione
per smartphone (Android ad esempio) sarà certamente diversa da quella del sito
MeCloud o da un'applicazione desktop di MeCloud.
Per
quanto riguarda la sicurezza, possono accedere a Mecloud Service WS solo gli
API Key prememorizzati nel database, cioè solo le applicazioni autorizzate.
Questi
parametri (API Key e TokenID) vengono cifrati (mediante la chiave pubblica) e
codificati in base64 dal sito in php e poi inviati via SOAP al web service
MeCloud Service, il quale provvederà a decodificarli e decriptarli mediante il
binomio chiave pubblica e privata tipico di un sistema di cifratura asimmetrico
.
Anche il
Web Service HTTP (il secondo web service integrato in MeCloud) usa il sistema
di decifraggio RSA per decriptare il TokenID dell'utente e creare la path
virtuale verso il file, il quale viene inviato in streaming.
I dati
binari trasferiti tra l'utente e il sito
e tra il sito e il web service non sono cifrati. Cifrare tutti i dati
“costerebbe” significativamente sulle performance fino a rendere il servizio
inutilizzabile.
D'altro
canto non è possibile tirar fuori i dati dal WS manualmente poiché il TokenID
della sessione è sempre trasferito cifrato.
Ecco la
funzione (php) di cifratura :
function encryptAndEncodeToBase64($data){
$server_public_key =
openssl_pkey_get_public(file_get_contents("certificates/publickey.pem"));
openssl_public_encrypt($data, $encrypted, $server_public_key);
return base64_encode($encrypted);
}
Ecco la
funzione di decriptaggio in c#:
Carico
le chiavi e creo l'oggetto RSA che mi permetterà di effettuare il decriptaggio
if(myCert2 == null || rsa == null){
myCert2
= new
X509Certificate2(certificatesPath+"mecloudprivatekey.pfx",privatePassw,X509KeyStorageFlags.MachineKeySet);
rsa = (RSACryptoServiceProvider)myCert2.PrivateKey;
}
e per
decriptare :
byte[] decrpyted =
rsa.Decrypt(Convert.FromBase64String(encryptedBas64Password), false);
String loginPwd =
System.Text.Encoding.UTF8.GetString(decrpyted);
decrpyted
= rsa.Decrypt(Convert.FromBase64String(encryptedBase64APIKey), false);
String ApiKey =
System.Text.Encoding.UTF8.GetString(decrpyted);
Il
database MySQL interno a MeCloud è protetto da password e non accetta
connessioni in ingresso da host non autorizzati. In questo caso ho
opportunamente modificato il file /etc/hosts facendo in modo che l'unico host
autorizzato sia il loop back device, ovvero localhost (127.0.01).
MeCloud
usa un sistema di passaggio di TokenID su url e mediante l’uso di cookie contenente
il TokenID. Quando l’utente effettua il logout, il cookie relativo alla
sessione viene cancellato (si imposta la scadenza ad un numero molto
precedente) e l'utente è costretto ad effettuare nuovamente il login.
Interfacciamento
tra PHP e MeCloudService Web Service
Invece
di utilizzare direttamente la classe SoapClient messa a disposizione dagli
sviluppatori di PHP, ho deciso di generarmi in automatico una classe wrapper
chiamata MeCloudService.php che si occupa di invocare i metodi tramite
SoapClient e ritornare i valori ricevuti dal web service.
Il tool
usato si chiama WSDLInterpreter e genera in automatico la classe PHP mediante
l'analisi del WSDL di Mecloud Web Service.
Il
protocollo usato per l'interscambio di informazioni è SOAP. Soap permette di
trasferire “buste” XML contenenti dati serializzati. XML è anche usato in altri
protocolli come XML-RPC ed ecc...
Avrei
potuto usare Json invece di XML risparmiando banda e tempo di trasferimento dei
dati, ma a discapito della compatibilità.
In
futuro MeCloud sarà implementato mediante chiamate asincrone (tipo Ajax) e
scambi di dati tra il broswer, il lato server del sito e il Web Service.
A titolo
informativo, sono in corso alcune polemiche riguardo l'uso di Ajax browser
side... si pensa che l'uso abbondante di questa tecnologia nelle pagine
dinamiche sia fonte di exploit (fondamentalmente Cross Site
Scripting e Denial Of Service) andando contro la sicurezza degli utenti, dei
loro dati e del servizio offerto. Per questo motivo si stanno implementando
nuovi protocolli come WebSocket. Sto quindi pensando di implementare MeCloud
con chiamate SOAP asincrone lato server per poi portare in “superficie” solo il
risultato senza invocare il Web Service esterno direttamente da javascript
(browser side).
Cioè
login e password vengono inviate “Server side” e ciò che il Web Service ritorna
viene prima elaborato dal lato server del sito e poi portato in superficie
rendendolo disponibile ai controlli in javascript.
Esempio
di invocazione del Web Service MeCloudService con PHP
Per
l’invocazione del WS di MeCloud via PHP ho generato la classe
MeCloudService.php.
L’uso è
il seguente:
Innanzitutto
bisogna includere tale classe nel sorgente con questa istruzione:
require_once("MeCloudService.php");
Qui di
seguito ci sono le istruzioni per invocare il web service. Nell’esempio
recupererò l’userid e la mail dell’utente invocando il metodo GetUserInfo del
web service.
$mecloud = new MeCloudService();
$parameters = new GetUserInfo();
$parameters->encryptedBase64Token = encryptAndEncodeToBase64($TokenID);
$parameters->encryptedBase64APIKey =
encryptAndEncodeToBase64("FLJQPZTXOEXWOJGLXZLMDPSEQPOQWYXO");
$response =
$mecloud->GetUserInfo($parameters)->GetUserInfoResult;
//la variabile $response contiene il valore:
userid,mail
//ora divido (split) la stringa in 2 paramtri
userid e mail
$temp = explode(",",$response);
$userid = $temp[0];
$mail = $temp[1];
Il
Database di MeCloud
Per
migliorare le performance ho ridotto al minimo l'uso di join e ogni selezione è
fatta basandosi unicamente dagli ID dei vari elementi. Addirittura la tabella
con più elementi è la tabella USERSTO ITEM la quale ha solo due campi
rappresentati dagli ID. Le performance, nonostante le basse capacità della
macchina virtuale, sono abbastanza soddisfacenti.
Il software è rilasciato gratuitamente per l'utilizzo, ma non può essere modificato ne integralmente ne in parte. Dal software in questione non possono essere copiati pezzi di codice o risorse varie.
Scaricando il software si accettano le suddette condizioni d'uso.
(c) 2011 by Vincenzo Dentamaro