lunedì 13 settembre 2010

Upload di file su Sharepoint 2010 + IIS 7 + NTLM con Java

immagine sorgente (GPL licensed)

Introduzione

L'articolo di oggi non è sicuramente una guida completa sulle modalità di comunicazione tra un'applicazione java ed un server Sharepoint ma vuole essere la descrizione di un caso d'uso reale che ho affrontato.
Per chi non conoscesse il prodotto di MS Sharepoint l'invito è di fare una veloce ricerca in rete per farsene un'idea. E' per lo più rivolto a soluzioni enterprise e offre una piattaforma di scambio di informazioni e documenti integrato nei sistemi Microsoft. In generale per quel poco che lo conosco è decisamente un prodotto interessante ma come spesso accade per i prodotti di Redmond l'interoperabilità con altre realtà software non è sempre delle più documentate e semplici

Cenni preliminari
Sharepoint ha un modulo web che si poggia sul server IIS di Microsoft. Per la comunicazione con applicativi esterni vengono forniti dei web-services e il supporto a WebDAV (o meglio ad una sua estensione marcata MS). Per i nostri scopi e per la problematica realmente affrontata descriverò il secondo approccio. Per il primo rimando a diversi articoli disponibili in rete tra cui questo.
WebDAV, acronimo di (Web-based Distributed Authoring and Versioning) è un insieme di metodi basati su HTTP e pensati per la pubblicazione e gestione di documenti e file attraverso il web. Il documento di specifiche è il RFC4918

Ambiente e condizioni al contorno
  • Applicativo java che deve creare una struttura di cartelle e file in Sharepoint
  • Sharepoint 2010 con supporto a WebDAV
  • IIS 7.5 con autenticazione NTLM
Strumenti utilizzati
Per poter effettuare una comunicazione con Sharepoint attraverso WebDAV ho utilizzato le seguenti librerie di supporto:
Le prime due offrono un client generico per HTTP mentre Sardine è un client specifico per WebDAV. A differenza di altri articoli per le mie esigenze ho voluto utilizzare una delle ultime versioni del client di Apache e per le quali non esiste ancora il porting della libreria alternativa a Sardine, jackrabbit. La scelta è anche motivata dal problema che esporrò in seguito con il modulo di autenticazione di ISS, NTLM.

Problematiche relative all'autenticazione con NTLM
In generale la documentazione delle librerie presentate è sufficiente per la maggior parte degli usi a meno che ISS non abbia impostata l'autenticazione con protocollo NTLM che mi ha dato non pochi problemi visto che non è ben documentata e che le librerie principali in Java non la supportano per questioni di incompatibilità di licenze. Una soluzione viene comunque fornita da Apache HttpClient in questo articolo. Si fa riferimento ad un hook del client di Apache che permette di registrare un proprio motore di autenticazione NTLM basato sulla libreria Java JCIFS. JCIFS è una libreria che implementa il protocollo CIFS/SMB in JAVA. L'uso è ben documentato nell'articolo linkato nel paragrafo. Noi ci concentriamo ora una volta aggiunto il motore NTLMEngine al client di come fare l'upload di un file.

Eseguire il PUT con WebDAV di Sharepoint e NTLM
Una volta superato l'impiccio dell'autenticazione per il metodo standard PUT si rendono necessari degli accorgimenti suggeriti da questo articolo della Microsoft e propri per ISS versione 7.x e successivi:
  • Aggiungere l'header “Translate: f” alle request di tipo PUT. Riferimento
Seguire i seguenti passi:
  1. Primo PUT senza contenuto per creare la risorsa nel percorso desiderato (concetto simile ad un touch in bash)
  2. un HEAD usato come pre-autenticazione
  3. PUT con il contenuto da caricare sul server nel corpo del body della request, con l'accorgimento che l'entity della request sia ripetibile, come per esempio un ByteArrayEntity.
Sardine non supporta NTLM per i motivi descritti precedentemente. Per ovviare al problema ho implementato l'interfaccia Sardine, prendendo spunto dal codice della sua implementazione in libreria SardineImpl passando al costruttore un client http già configurato per il supporto a NTLM e bypassando la factory della libreria. Inoltre i metodi put() seguono i tre passi appena descritti. Il codice del put riscritto nella mia implementazione di Sardine è più o meno questo:
public void put(String url, byte[] data) throws SardineException
{
// primo put
HttpPut putTouch = new HttpPut(url);
putTouch.setHeader("translate", "f");
HttpResponse response = this.executeWrapper(putTouch);
StatusLine statusLine = response.getStatusLine();
putTouch.abort();
if(!SardineUtil.isGoodResponse(statusLine.getStatusCode()))
{
 throw new SardineException(url, statusLine.getStatusCode(),
   statusLine.getReasonPhrase());
}
// head
HttpHead head = new HttpHead(url);
response = this.executeWrapper(head);
statusLine = response.getStatusLine();
head.abort();
if(!SardineUtil.isGoodResponse(statusLine.getStatusCode()))
{
 throw new SardineException(url, statusLine.getStatusCode(),
   statusLine.getReasonPhrase());
}
// secondo put con il contenuto
HttpPut put = new HttpPut(url);
put.setHeader("translate", "f");
ByteArrayEntity entity = new ByteArrayEntity(data);
put.setEntity(entity);
response = this.executeWrapper(put);
statusLine = response.getStatusLine();
put.abort();
if(!SardineUtil.isGoodResponse(statusLine.getStatusCode()))
{
 throw new SardineException(url, statusLine.getStatusCode(),
   statusLine.getReasonPhrase());
}
}


Conclusione
Dopo aver passato alcuni giorni lavorativi tra trace di header e message HTTP posso dire che spesso le aziende si fanno convincere nell'utilizzo di protocolli chiusi, in nome della sicurezza e della facilità di gestione andando poi a perdere gli investimenti iniziali nelle realizzazioni di integrazioni con altri prodotti che non siano MS.
Per chi mi conosce ci voleva questa nota pro Open Source!!!

0 commenti:

Posta un commento