Qualche tempo fa ho scritto un post un po' polemico sulla realizzazione di un MebershipProvider per SharePoint e Massimo Prota nei commenti mi invitava a dettagliare i problemi che ho incontrato.
Finalmente eccoci Tongue out, tempo tiranno...
Cominciamo con l'introdurre lo scenario:
Lo scopo era quello di realizzare un "Proof of Concept" (belli questi paroloni...) per un potenziale cliente che vorrebbe migrare una corposa (decisamente corposa) applicazione dall'accoppiata Domino/Notes a non si sa bene che cosa e una delle possibili soluzioni è proprio SharePoint.
Uno dei punti oscuri era proprio la necessità di implementare, in alcuni scenari, un sistema di autenticazione custom, quindi non basato sulla Windows Authentication (che è il default). Questo perchè il 90% dei fruitori dell'applicazione è in modalità ASP ma c'è un 10% che ha delle installazioni custom presso di loro e non è pensabile imporre al cliente finale un doppio sistema di autenticazione con tutti problemi di manutenibilità che questo comporta...
Una delle cose fenomenali, in questa direzione, è che essendo SharePoint implementato sull'engine di Asp.NET 2.0 può beneficiare dei MembershipProvider di Asp.NET esattamente come qualsiasi altra applicazione web, non male! decisamente non male, e non è tutto qui...
Fatte queste premesse ho cercato di riprodurre lo stesso scenario con una mia applicazione, ho quindi preso una semplice applicazione Windows Forms (un gestionale dei più normali), che sto sviluppando, che fa uso di un sistema di autenticazione custom e mi sono detto: bene! adesso voglio avere un sito di SharePoint che utilizza lo stesso motore di autenticazione della mia applicazione e già che ci siamo una bella Webpart che mi visualizzi l'anagrafica clienti.
Essendo l'applicazione Windows Forms un'applicazione n-tier è stato decisamente semplice scrivere un MembershipProvider che facesse da adattore verso il tier che gestisce l'autenticazione nella mia applicazione. Qui mi preme fare comunque qualche considerazione anche se esula dal contesto:
  • perchè se c'è già una meravigliosa struttura (IPrincipal/IIdentity) è stato introdotto il MembershipUser? ma soprattutto perchè è una classe e non un'interfaccia? mi sembra una scelta pessima;
  • Lo stesso ragionamento lo farei per MembershipProvider, perchè non è un'interfaccia? sarebbe stato decisamente più semplice in scenari come quello che sto affrontando adesso;
Detto questo torniamo al nostro problema...
Una volta costruito il MembershipProvider, operazione direi abbastanza banale, tediosa ma banale ci dobbiamo sorbire l'implementazione del MembershipUser che oserei definire ancora più tediosa.
Realizzata l'infrastruttura non ci resta che testarla e qui il primo problema...il sistema più banale per eseguire qualche test è creare una applicazione web, inserire i riferimenti al MembershipProvider nel web.config e poi utilizzare il WebSite Administration Tool (per gli amici WAT). Facciamo partire il tutto e si schianta che è un piacere...molto bene... Sarcastic una rapida ricerca su Google e un po' di debug e scopro che se definite un vostro MembershipUser l'assembly, perchè venga digerito dal WAT, deve stare in GAC, ma stiamo scherzando? una menata mai vista, quindi molla al volo il WAT e costruisci un semplice sitarello per fare le stesse cose che fa il WAT.
A questo punto prima di fare i test con SharePoint, utilizzando il mio MembershipProvider rischando di cadere in problemi simili, seguo gli esempi che ho trovato a bizzeffe su internet che fanno tutti uso del SqlMembershipProvider builtin di Asp.NET e...qui casca l'asino Smile (il primo...)
Metto in piedi quindi un WebSite vuoto lo configuro per usare il SqlMembershipProvider (seguendo quello che fanno tutti gli esempi) e creo qualche utente sempre usando il WAT che a questo punto funziona... per forza sta in GAC...
Fatto questo configuro SharePoint per utilizzare il SqlMembershipProvider, l'operazione è decisamente semplice e ben documentata su MSDN. E' importante creare gli utenti prima perchè una volta cambiato il provider in SharePoint non avrete più mezzo di accedere al portale... e qui casca il secondo asino: ci sono due/tre possibili soluzioni, che nessuno cita... lasciandomi presagire che nessuno degli scriventi ci abbia realmente provato:
  • per garantire comunque l'accesso è possibile, soluzione più semplice anche se poco utile in effetti, attivare l'accesso anonimo e il tutto va come prima, unico problema è che comunque per accedere alle sezioni di configurazione di SharePoint bisogna loggarsi e i nostri utenti custom non hanno permessi (non appartengono a nessun ruolo) in SharePoint;
  • La seconda possibilità è quella di usare le Policy di SharePoint direttamente dal sito di amministrazione di SharePoint e abilitare quindi uno degli utenti custom a poter fare tutto;
  • Terza possibilità è inserie, sempre dal tool di amministrazione di SharePoint, il Collection Administrator corretto, questa secondo me è la soluzione migliore;
Fatto questo tutto dovrebbe funzionare, quindi proviamo ad accedere al nostro sito di SharePoint e al primo tentativo di autenticazione si schianta tutto, o meglio non c'è mezzo di fargli digerire la password... "ma pecchè..." Sarcastic
Qui all'inizio mistero... e San Google non è stato d'aiuto (anche perchè non sapevo cosa cercare...) un po' di analisi della configurazione, e un po' di c..o, mi hanno fatto scoprire la magagna, e qui casca il terzo asino..., in buona sostanza è un problema di crittografia della password, il WAT in collaborazione con il SqlMembershipProvider utilizza per crittografare/decrittografare le password la MachineKey definita nel machine.config, ogni sito di SharePoint ridefinisce questo valore causando il problema appena descritto, il logon infatti non avviene perchè la password presente nel db viene decrittografata con una Key diversa... ribadisco ma la gente le prova o scrive per sentito dire....
A questo punto non avevo nessuna voglia di capire se cambiando al MachineKey ridefinita nel sito di SharePoint le cose avrebbero cominciato a funzionare per il semplice fatto che non volevo poretarmi a casa altre magagne.
Predno quindi il mio MembershipProvider e lo butto dentro nella directory bin dell'applicazione di SharePoint, rimuovo un po' di magagne legate alla CAS (questa è un'applicazione di esempio e quindi mi andava bene che girasse in Full Trust, mentre SharePoint non gira di default in Full Trust... ed è cosa ottima) e riprovo ad autenticarmi...

Bingo! va che è una meraviglia!!!
Un'ultima nota, perchè sia possibile amministrare i nostri utenti anche dal Tool di amministrazione di SharePoint è necessario configurare anche lui per utilizzare il nostro MembershipProvider custom.
.m