Ecco come integrare i servizi di sinekarta in qualsiasi software!
settembre 20, 2011 Lascia un commento
Come vi ho spiegato nello scorso articolo, con la versione 2.0 sinekarta è stato APERTO; i servizi che mette a disposizione sono utilizzabili da qualsiasi software.
Questo articolo vuole spiegare, tramite esempi, come integrare alcuni (tra i diversi) servizi di sinekarta.
Prima di continuare a leggere è importante sapere alcune cose :
- Se non hai un background informatico probabilmente non capirai un gran che di questo articolo (nel caso forse ti basterà sapere che si può fare ed è facile)
- Gli esempi di codice inseriti in questo articolo sono scritti in Java, probabilmente sul wiki di progetto, in futuro, sarà possibile reperire esempi in altri linguaggi.
- I servizi REST esposti da sinekarta sono realizzati in duplice versione : con input/output in formato JSON e con input/output in formato XML; questo esempio usa il formato JSON
- Sul repository SVN di progetto potete trovare i sorgenti di questo articolo e di altri client di esempio
Quello che andremo a realizzare tramite questo esempio è un programma che prende un documento (già inserito nel repository Alfresco), lo converte in PDF/A ed applica la firma digitale di un utente.
Per poter eseguire questo codice senza errori avete quindi bisogno di :
- Alfresco 3.4d (o superiore) correttamente installato
- Sinekarta 2.0 beta (o superiore) correttamente installato e configurato
- Un IDE per lo sviluppo (es. Eclipse) su cui installare gli esempi di sinekarta (potete scaricarli da questo repository SVN : https://sinekarta.svn.sourceforge.net/svnroot/sinekarta/trunk/SinekartaAlfrescoClient; il sorgente di questo articolo è la classe java org.sinekarta.alfresco.webscripts.TestDigitalSignature)
- Un lettore di smart card correttamente installato e funzionante con relativa smart card di firma digital (in alternativa potete utilizzare un token USB)
Come prima cosa è necessario convertire il documento prescelto in PDF/A. Come sapete questo formato non prevede macro istruzioni nè codice eseguibile, compatibilmente con la normativa Italiana in materia :
// step 1 : conversione in PDF/A // operazione lato server ... HttpPost httppost = new HttpPost(DOCUMENT_TO_PDFA); // prima di tutto, il documento va convertito in PDF/A // la action lavora sul documento stesso, quindi se non si // vuole perdere l'originale è opportuno lavorare su una copia String req = "{"nodeRefs":""+nodeRefId+""}"; ByteArrayEntity body = new ByteArrayEntity(req.getBytes()); httppost.setEntity(body); HttpResponse response = httpclient.execute(targetHost, httppost, localcontext); HttpEntity entityResp = response.getEntity(); InputStream is = entityResp.getContent(); JSONObject inputJson=null; try { inputJson = JSONObject.fromObject(new String(loadResponse(is), ENCODING)); } catch (UnsupportedEncodingException e) { // not possible } System.out.println(inputJson); EntityUtils.consume(entityResp);
Sono stati volutamente omesse alcune righe di codice, quelle più insignificanti dal punto di vista di sinekarta.
Il servizio prende un elenco di nodeRef separti tramite il carattere “,” (virgola). Ogni singolo nodeRef è una stringa simile a questa : workspace://SpacesStore/87350b02-32ab-4787-98d0-3daa1c0b7b01. Questo servizio lavora direttamente sul documento indicato, quindi, se non volete perdere l’orignale, sarà meglio che lavoriate su una copia.
Piccola nota tecnica, il servizio di trasformazione in PDF/A di sinekarta è basato su open office, ma non è in conflitto con tutti i servizi di trasformazione messi a disposizione da Alfresco.
Ora che abbiamo un documento PDF/A è necessario eseguire 5 diversi step per l’applicazione della firma digitale. In particolare dovremo eseguire 3 step lato server e 2 step lato client. Se non avete idea del perchè parli di due diversi strati applicativi, andatevi a rileggere questo articolo.
Sia che lo abbiate letto, o che non lo abbiate fatto, ve lo riassumo in due parole : la comunicazione con la smart card è un’attività che DEVE essere fatta dal client, l’applicazione della firma al documento PDF/A è un’attività che viene fatta lato server.
Il secondo passo da eseguire è l’inizializzazione dell’algoritmo di firma digitale sui PDF/A :
// step 2 : inizializzazione procedura di firma // operazione lato server ... HttpPost httppost = new HttpPost(DIGITAL_SIGNATURE_INIT); // bisogna ora inizializzare la procedura di firma digitale per // ottenere l'handle // l'handle ricevuto va poi passato alle chiamate successive // nessun documento viene modificato in questa fase // devo passare l'handle di una directory parent comune // di tutti i documenti che andrà a firmare String req = "{"nodeRef":""+parentNodeRefId+""}"; ByteArrayEntity body = new ByteArrayEntity(req.getBytes()); httppost.setEntity(body); HttpResponse response = httpclient.execute(targetHost, httppost, localcontext); HttpEntity entityResp = response.getEntity(); InputStream is = entityResp.getContent(); JSONObject inputJson=null; try { inputJson = JSONObject.fromObject(new String(loadResponse(is), ENCODING)); } catch (UnsupportedEncodingException e) { // not possible } System.out.println(inputJson); // imposto l'handle per la prima volta, viene sempre ripassato // alle chiamate successive digitalSignatureArea = inputJson.getString("digitalSignatureArea"); EntityUtils.consume(entityResp);
Eseguita questa attività (lato server) abbiamo inizializzato l’algoritmo di firma. Abbiamo passato come parametro il nodeRef dello space parent del documento che andrè firmato e riceviamo come risultato un handle (digitalSignatureArea) che dovremo salvare e ripassare alle chiamate successive.
Ora che abbiamo inizializzato l’algoritmo, è necessario eseguire la prima operazione lato client, dobbiamo scegliere il certificato da utilizzare :
// step 3 : l'handle va passato al client di firma // (che parla con il lettore di smart card) per // eseguire la scelta del certificato // operazione lato client // il DRIVER ed il PIN dipendono dall'utente, li dovrebbe digitare lui // sinekarta espone un webscript che lista i driver definiti lato server // parto dal presupposto che ci sia solo un certificato caricato nella // smart card, uso il primo per la firma SinekartaDigitalSignatureClient client = new SinekartaDigitalSignatureClient(digitalSignatureArea); // importante : passare l'handle ricevuto in init client.setDriver(DRIVER); client.setPin(PIN); client.start(); // contatta il lettore di smart card per ottenere la lista // dei certificati Map<X509Certificate, String> list = client.certificateList(); // importante, aggiornare l'handle per ripassarlo // al server per la vase successiva digitalSignatureArea = (String)list.values().toArray()[0]; client.close();
Il client di firma è attualmente disponibile solo in java, se qualche bravo sviluppatore volesse crearne una versione in un linguaggio diverso, è bene accetto. In caso dobbiate implementare un client web, il client è disponibile anche sottoforma di applet.
Al client vanno passati due parametri importanti : il driver da utilizzare per accedere alla smart card (leggi qui per saperne di più) ed il PIN per accedere ai servizi della carta.
L’handle ritornato dalla fase di inizializzazione (step 2) viene passato al client di firma che restituisce un elenco di certificati. A ciascun certificato è associato il nuovo handle che dovrà essere passato avanti.
L’utente dovrà scegliere tra i certificati restitutiti (list.values().toArray()) quello che intende utilizzare, per semplicità l’esempio prende il primo.
Una volta scelto il certificato è necessario chiamare un secondo servizio sinekarta lato server che calcola l’impronta del documento :
// step 4 : preparo i dati di firma per il/i documento/i da firmare // questo step può essere ripetuto tante volte, quanti sono i // diversi motivi di firma // ogni chiamata può contenere diversi documenti, verranno tutti // firmati con lo stesso motivo (descrizione) di firma // operazione lato server ... HttpPost httppost = new HttpPost(DIGITAL_SIGNATURE_PREPARE_AND_ADD); // per ciascun documento (o elenco di documenti a parità di descrizione) // devono essere calcolati i dati di firma // importante : l'handle restituito dal client di firma va ripassato // non vengono modificati documenti in questa fase String req = "{" + ""digitalSignatureArea" : ""+digitalSignatureArea+"", " + ""signDescription" : ""+descrizioneMotivoFirma+"", " + ""signLocation" : ""+localitaFirma+"", " + ""nodeRefs":""+nodeRefId+""" + "}"; ByteArrayEntity body = new ByteArrayEntity(req.getBytes()); httppost.setEntity(body); HttpResponse response = httpclient.execute(targetHost, httppost, localcontext); HttpEntity entityResp = response.getEntity(); InputStream is = entityResp.getContent(); JSONObject inputJson=null; try { inputJson = JSONObject.fromObject(new String(loadResponse(is), ENCODING)); } catch (UnsupportedEncodingException e) { // not possible } System.out.println(inputJson); // il server ha processato i dati di firma, recupero il nuovo // handle da passare al client digitalSignatureArea = inputJson.getString("digitalSignatureArea"); EntityUtils.consume(entityResp);
In questa seconda chiamata server devono essere indicati alcuni dati importanti : prima di tutto l’handle che ci è stato restitutito dal client nella fase di scelta del certificato (digitalSignatureArea). Poi devono essere passati due dati descrittivi che indicano la descrizione del motivo di firma e la località in cui viene apposta la firma (signDescription, signLocation). Alla fine viene passato l’elenco (separato da “,”) dei nodeRef che devono essere digitalmente firmati. Anche in questo caso il formato dei nodeRef deve essere tipo questo : workspace://SpacesStore/87350b02-32ab-4787-98d0-3daa1c0b7b01
Ciascun documento indicato deve essere un PDF/A.
Anche in questo caso il servizio di sinekarta torna l’handle modificato che deve essere passato alla fase successiva.
L’impronta calcolata deve essere digitalmente firmata, deve quindi essere calcolata la firma digitale :
// step 5 : l'handle va passato al client di firma // (che parla con il lettore di smart card) // per eseguire la vera e propria firma // operazione lato client SinekartaDigitalSignatureClient client = new SinekartaDigitalSignatureClient(digitalSignatureArea); // attenzione : gli passo l'handle ricevuto dalla fase 4 client.start(); // è importante aggiornare l'handle con i dati ricevuti dal client digitalSignatureArea = client.executeDigitalSignature(null); // potrei passargli un listener che mi avvisa dell'avanzamento, // ma per questo test è inutile client.close();
Anche in questo caso è necessario passare al client l’handle che verrà restituito modificato per la fase successiva.
Come ultimo passo è necessario applicare la firma digitale al documento PDF/A, ecco come :
// step 6 : chiudo e applico la firma a tutti i documenti; // da eseguire una sola volta alla fine del processo // operazione lato server ... HttpPost httppost = new HttpPost(DIGITAL_SIGNATURE_APPLY); // devo passare l'handle ricevuto dal client // devo passare l'handle di una directory parent comune // di tutti i documenti che andrà a firmare // i documenti vengono aggiornati solo in questa fase. // la procedura lasciata a metà non modifica i documenti // PDF precedentemente creati String req = "{" + ""digitalSignatureArea" : ""+digitalSignatureArea+"", " + ""nodeRef":""+parentNodeRefId+""" + "}"; ByteArrayEntity body = new ByteArrayEntity(req.getBytes()); httppost.setEntity(body); HttpResponse response = httpclient.execute(targetHost, httppost, localcontext); HttpEntity entityResp = response.getEntity(); InputStream is = entityResp.getContent(); JSONObject inputJson=null; try { inputJson = JSONObject.fromObject(new String(loadResponse(is), ENCODING)); } catch (UnsupportedEncodingException e) { // not possible } System.out.println(inputJson); EntityUtils.consume(entityResp);
Il servizio riceve in input l’handle (digitalSignatureArea) che ci siamo portati dietro dall’inizio e il nodeRef dello space parent del documento che abbiamo firmato; lo stesso che abbiamo passato al momento dell’inizializzazione (step 2).
Se le 5 (+1) fasi si sono completate correttamente, abbiamo applicato correttamente la firma digitale al nostro documento.
Ora potete divertirvi anche in autonomia ad utilizzare i servizi di sinekarta.
Sinekarta espone diversi servizi, tutti in modalità simili a quelle esposte in questo articolo. Più avanti esploreremo altri servizi.