Creare un meccanismo di autentificazione Forms-Based per un'applicazione SharePoint Foundation utilizzando il Membership ed il Role Providers di ASP.NET SQL

Premessa doverosa: per raggiungere l'obiettivo del titolo di questo post ho impiegato più di 8 ore di lavoro leggendo e rileggendo documentazione tecnica Microsoft, blog tecnici e quanto altro. Spero che il mio post sia di aiuto a molti lettori; comunque lo sarà per me nei prossimi deployment. Il documento MSDN che prenderò come riferimento è il seguente http://msdn.microsoft.com/en-us/library/gg252020.aspx (che deve essere adattata per Sharepoint Foundation). Allo stesso modo suddividerò la trattazione per passi successivi.
 

STEP 1: Preparazione del Database al fine di utilizzare il Membership ed il Role Provider ASP.NET per le applicazioni web

Eseguiamo il file aspnet_regsql.exe contenuto nella cartella C:\Windows\Microsoft.NET\Framework64\v2.0.50727. Verrà avviata una procedura guidata che consentirà facilmente di creare il database che verrà utilizzando dal Provider. Sarà sufficiente selezionare l'istanza del Server di Database (WIN-02F9XCJAEJX\SQLEXPRESS nel mio caso) ed assegnare il nome al database (aspnetdb_claim)

STEP 2: Aggiungere utenti e ruoli al Database del Provider dei Ruoli e dei Membri

Avviare Microsoft SQL Server Management Studio ed eseguire le seguenti query sul db aspnetdb_claim database:
declare @now datetime
set @now= GETDATE()
exec aspnet_Membership_CreateUser 'MyAppName','admin','pwadmin',
    '','admin1@contoso.com','','',1,@now,@now,0,0,null
 
EXEC aspnet_Roles_CreateRole 'MyAppName', 'Administrator'
EXEC aspnet_UsersInRoles_AddUsersToRoles 'MyAppName', 'admin', 'Administrator', 8
 

STEP 3: Creare un'applicazione di Sharepoint Foundation

 
Seguire la seguente procedura
  1. Aprire SharePoint 2010 Central Administration
  2. In Application Management section, cliccare su Manage web applications.
  3. Sulla ribbon (striscia superiore della finestra) cliccare su New. Si creerà una nuova applicazione con dei valori default: assumiamo in questo esempio che la porta sia la numero 8676 e l'url pubblico sia http://WIN-02F9XCJAEJX:8676/ (WIN-02F9XCJAEJX è il nome del server dove state eseguendo il deployment)
  4. Nella finestra di dialogo, nella sezione Authentication, scegliere Claims Based Authentication.
  5. In Claims Authentication Types section, selezionare Enable Forms Based Authentication (FBA) e deselezionare tutte le altre opzioni (in particolare Enable Windows Authentication e Integrated Windows authentication)
  6. Nella casella di testo "ASP.NET membership provider name" immettere aspnetmembership, nel campo "ASP.NET role manager name" svrivere  aspnetrolemanager
  7. Nella sezione "Database Name and Authentication", cambiare il nome del db da WSS_Content a WSS_Content_8676 ed assicurarsi che il database server sia WIN-02F9XCJAEJX\Sqlexpress, dove abbiamo creato il dabase dei ruoli e membri.
  8. Lasciare le altre opzioni invariate

STEP 4: Configurare il Membership ed il Role Provider per l'applicazione Sharepoint Foundation

Questo step prevede la modifica di:
  1. Central Administration
  2. Security Token Service
  3. FBA Web Application
E' necessario innanzitutto identificare il web.config della SharePoint 2010 Central Administration: a tal proposito è possibile ad esempio servirsi di IIS Manager ed espolare il sito "SharePoint Central Administration v4". Nel mio caso la directory di appoggio della Central Administration si trova in C:\inetpub\wwwroot\wss\VirtualDirectories\32388.
Sostituire il web.config con web.config (46,21 kb). Di fatto sarebbe stato sufficiente inserire nel web.config la segunte stringa di connessione appena dopo </configSections>
<connectionStrings>
    <clear />
    <add name="AspNetSqlMembershipProvider" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim"
      providerName="" />
    <add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb_claim;data source=.\Sqlexpress;Integrated Security=SSPI;" />
  </connectionStrings>
ed il seguente codicie
<roleManager enabled="true" cacheRolesInCookie="false" cookieName=".ASPXROLES"
      cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true"
      cookieProtection="All" defaultProvider="AspNetWindowsTokenRoleProvider"
      createPersistentCookie="false" maxCachedResults="25">
      <providers>
        <clear />
        <add connectionStringName="AspNetSqlMembershipProvider" applicationName="/"
          name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add applicationName="/" name="AspNetWindowsTokenRoleProvider"
          type="System.Web.Security.WindowsTokenRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetrolemanager"
             type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName" />
      </providers>
    </roleManager>
    <membership defaultProvider="AspNetSqlMembershipProvider" userIsOnlineTimeWindow="15"
      hashAlgorithmType="">
      <providers>
        <clear />
        <add connectionStringName="AspNetSqlMembershipProvider" enablePasswordRetrieval="false"
          enablePasswordReset="true" requiresQuestionAndAnswer="true"
          passwordAttemptWindow="10" applicationName="/" requiresUniqueEmail="false"
          passwordFormat="Hashed" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetmembership"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName"
             type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
nel <system.web>, andando a sostituire i tag <roleManager> e <membership> se già estenti.
Sempre mediante IIS identificare SharePoint Web Services ed esplorare SecurityTokenServiceApplication. Nel nostro caso si verrebbe reindirizzati alal seguente cartella C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\WebServices\.
Sostituire il web.config presente con web.config (6,73 kb), oppure aggiungere al web.config già presente il seguente codice appenda dopo <configuration>
<connectionStrings>
    <clear />
    <add name="AspNetSqlMembershipProvider" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim"
      providerName="" />
    <add name="MyLocalSQLServer" connectionString="Initial Catalog=aspnetdb_claim;data source=.\Sqlexpress;Integrated Security=SSPI;" />
  </connectionStrings>
e la sezione seguente appena prima di </configuration>:
<system.web>
    <roleManager enabled="true" cacheRolesInCookie="false" cookieName=".ASPXROLES" cookieTimeout="30" cookiePath="/" cookieRequireSSL="false" cookieSlidingExpiration="true" cookieProtection="All" createPersistentCookie="false" maxCachedResults="25">
      <providers>
        <add connectionStringName="AspNetSqlMembershipProvider" applicationName="/" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
        <add name="aspnetrolemanager" 
             type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName" />
      </providers>
    </roleManager>
    <membership userIsOnlineTimeWindow="15" hashAlgorithmType="">
      <providers>
        <add connectionStringName="AspNetSqlMembershipProvider" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="true" passwordAttemptWindow="10" applicationName="/" requiresUniqueEmail="false" passwordFormat="Hashed" name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
 	<add name="aspnetmembership"
             connectionStringName="MyLocalSQLServer"
             applicationName="MyAppName"
             type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
 </system.web>
Infine è necessario sostituire il web.config della nostra applicazione web allocata in C:\inetpub\wwwroot\wss\VirtualDirectories\8676 con web.config (48,19 kb) o in alternativa modificare il file di configurazione già presente aggiungendo:
<connectionStrings>
    <add name="MyLocalSQLServer" connectionString="data source=.\Sqlexpress;Integrated Security=SSPI;Initial Catalog=aspnetdb_claim" providerName="" />
  </connectionStrings>
subito dopo </configSections> e
<membership defaultProvider="i">
      <providers>
        <add name="i" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthMembershipProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="aspnetmembership" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
      </providers>
    </membership>
    <roleManager defaultProvider="c" enabled="true" cacheRolesInCookie="false">
      <providers>
        <add name="c" type="Microsoft.SharePoint.Administration.Claims.SPClaimsAuthRoleProvider, Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
        <add name="aspnetrolemanager" type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="MyLocalSQLServer" applicationName="MyAppName" />
      </providers>
    </roleManager>
appena prima di </system.web>, sostituendo nel caso in cui esistano i tag già presenti.
 

STEP 5: Testare il modello di autentificazione

Utilizzando la Central Administration website, sotto Application Management cliccare su Create site collection.
Nella casella a discesa Web Application selezionare la nostra applicazione, http://WIN-02F9XCJAEJX:8676/ e quindi assegnare un titolo al sito. Nella texbox User name scrivere admin, ovvero il nome dell'utente che abbiamo inserito nel DB e controllare l'esistenza dell'utente.
Confermare la creazione del sito e nel browser digitare http://WIN-02F9XCJAEJX:8676/ . Se tutto funziona si viene reindirizzati ad una pagina di login dove si deve inserire lo user name admin e la password pwadmin.

STEP 6: Risolvere gli eventuali problemi

Il problema che io ho incontrato era legato alla non attivazione di Security Token Service Application . 

La risoluzione del problema è descritta nel seguente articolo http://support.microsoft.com/kb/2520344. In particolare ho dovuto assegnare al sito il livello di Trust Full.

Ottenere il PublicKeyToken di una dll

Per ricavare il Public Key Token di un assembly .NET è sufficiente utilizzare gli strumenti esterni di Visual Studio come recita il seguente articolo http://blogs.msdn.com/b/kaevans/archive/2008/06/18/getting-public-key-token-of-assembly-within-visual-studio.aspx.

Per chi come il sottoscritto utilizza Visual Web Developer Express, il metodo non è utilizzabile perché vincolato dal possesso di Visual Studio.

Un metodo semplice e a costo zero sussiste nell'accedere al direttorio C:\Windows\assembly e visualizzare le proprietà delle dll installate.

Nel caso in cui la dll non risultasse installata e quindi non fosse presente, sarebbe sufficiente "trascinarla" nel direttorio sopra menzionato.

Ottenere la versione di una dll

Per ottenere la versione di una dll è sufficiente creare il seguente file vbs utilizzando ad esempio blocco note:
set args = WScript.Arguments
Set fso = CreateObject("Scripting.FileSystemObject")
WScript.Echo fso.GetFileVersion(args(0))
Wscript.Quit
Salvare quindi il file con nome, ad esempio VersionInfo.vbs, in un direttorio qualsiasi
Aprire l'interfaccia a riga di comando (cmd.exe) ed eseguire dal path in cui si è salvato il file vbs:
cscript //nologo VersionInfo.vbs C:\Path\To\MyFile.dll
in cui MyFile.dll è la dll di cui si vuole conoscere la versione

SharePoint Foundation 2010: la mia prima installazione

C'è sempre una prima volta e per il sottoscritto oggi rappresenta l'iniziazione alla piattaforma Sharepoint che spero mi aprirà nuovi scenari di applicazione e sviluppo.

Di fatto già un anno fa mi ero sperimentato nell'utilizzo di Sharepoint acquistando un servizio hostato su http://www.apps4rent.com/.

Oggi invece ho installato SharePoint Foundation 2010 e l'SDK relativo sul mio notebook con sistema operativo Windows 7 Pro. Ho seguito come linea guida per l'installazione le seguenti istruzioni di Microsoft http://msdn.microsoft.com/en-us/library/ee554869.aspx.

Ora mi attende l'installazione sul server web di distribuzione ...

Google Maps Latitude, Longitude Grabber with Geocoding and Reverse Geocoding using Google Maps Javascript API V3 Services

Mi sto occupando dello sviluppo di un CMS per la gestione di SlideCake (www.slidecake.com). Ho così progettato una sezione per la modifica delle slide di tipo Google Maps utilizzando le API v3.

Alla seguente pagina http://www.sormanistudio.it/gmap/smap.htm è possibile testare la funzionalità "cuore" dell'applicazione. E' così possibile inserire l'indirizzo della location ed il codice si occuperà di geo-localizzare il punto restituendo la latitudine e longitudine dell'indirizzo.

Oppure inserendo le coordinate geografiche il servizio collocherà il luogo sulla mappa restituendo l'indirizzo (geo-localizzazione inversa) ed infine cliccando semplicemente sulla mappa verranno visualizzate le coordinate del punto e l'indirizzo esatto.

All'indirizzo http://www.sormanistudio.it/gmap/smap.zip sono disponibili in download i file sorgenti dell'applicazione.

 

FastWeb: superare il limite dei PC collegati in LAN

Di recente ho attivato un contratto SmallBusiness in teconologia HDSL per la fornitura del servizio di solo Internet integrandolo in una rete aziendale a dominio Windows 2003 Server. Solo dopo la configurazione del router da parte dei tecnici Fastweb mi sono reso conto che il contratto imponeva il limite di 55 PC collegati contemporaneamente in rete.

Tale limite viene comunque imposto anche nelle linee private ed impedisce la connessione contemporanea a non più di 3 PC.

Il superamento di questo vincolo può essere facilmente superato collegando ad una delle porte LAN del router FastWeb la porta Wan di un router (non router/modem) realizzando in questo modo una sotto-rete privata ed utlizzando soltanto 1 degli indirizzi messi a disposizione da FastWeb.

Di fatto viene già fatto accenno a questa tecnica nel seguente articolo http://www.qualeadsl.com/disdette/come-collegare-molti-piu-computer-contemporaneamente-con-fastweb_post-145.html

Per il router ho optato per un ASUS WL-520gU (http://www.asus.com/Networks/WiFi_Networking/WL520gU/#overview)

Obout: ASP.NET Controls

E' da circa 6 anni che nelle mie applicazioni web mi avvalgo della suite di controlli Obout (www.obout.com).

La suite offre agli sviluppatori .NET un set di controlli molto simili alla più nota suite Telerik ma ad un prezzo nettamente inferiore.

Con soli $ 199 è possibile acquistare i seguenti controlli: TreeView, Grid, HTML Editor, Spell Checker, Calendar, Easy Menu, Context Menu, Tab Strip, Combobox, AJAX Autosuggest, State Selector, Multilevel Combobox, Listbox, Multilevel Listbox, Super Form, Slide Menu, AJAX Page, Text Menu, Splitter, Tree_DB, Show, Flyout, Window, File Upload Progress, Color Picker, Scheduler, Interface Controls, Image Zoom.

L'assistenza offerta è andata via via dimunendo di qualità e puntualità con il passare degli anni ma è comunque soddisfacente: ultimamente la Società ha attivato un forum di discussione che sinceramente non ho ancora sperimentato.

A detta di Obout sono l'unico sviluppatore italiano ad utilizzare la loro suite!

ARVIXE web hosting e dintorni

In ogni lavoro che preventivo mi trovo nella necessità di dover consigliare al cliente un servizio di hosting che sia al tempo stesso performante con un'assistenza altamente qualificata ma anche economico. Premetto che io mi occupo esclusivamente di sviluppo su piattaforma Windows per cui l'hosting deve essere necessariamente Windows dotato di framework .NET aggiornato all'ultima versione, offrire la possibilità di attivare uno o più istanze di MS SQL SERVER, permettere la personalizzazione della configurazione di IIS, supportare il Full Trust ecc... Di fatto in Italia le due caratteristiche prima menzionate sembrano non poter coesistere per cui per avere un servizio efficiente, con un'assistenza professionale si deve spendere molto denaro.

Nel mio lavoro ho avuto modo di testare parecchi hosting ma mai nessuno mi ha soddisfatto pienamente: segnalo comunque che uno dei migliori hosting che abbia mai provato è DISCOUNTAsp (www.discountasp.com) ma purtroppo molti clienti si sono lamentati per la lentezza dell'hosting anche se i server risiedevano in europa.

Mi sono sono allora sperimentato nel testare diverse proposte cercando di escludere in un primo approcio i server oltreocenano perché come molte risorse tecniche recitano, le distanze di tali server dall'Italia aumentano inesorabilmente i tempi di latenza (http://www.hostingtalk.it/articoli/noamweb/3240/webhosting-server-scegliere-soluzione-ed-hoster?page=6).

Di fatto anche se l'asserzione di cui sopra è del tutto razionale, il tempo di risposta di una stessa applicazione non dipende solo dalla distanza dell'hosting ma anche dalla velocità di elaborazione del server (ovviamente).

Una testimonianza di quanto affermo è ARVIXE (www.arvixe.com) web hosting, i cui server sono collocati a Santa Rosa in California.

Ad un prezzo molto competitivo anche rispetto all'italiano ARUBA, ARVIXE offre un hosting condiviso, molto performante e dotato di molte caratteristiche e peculiarità in Italia introvabili. L'assistenza, 7 giorni su 7, è molto professionale e cordiale.

Dopo aver testato l'hosting per 1 mese con un'applicazione molto complessa, ho deciso di affidarmi ad ARVIXE per tutti le mie applicazione. L'unico neo è che per ora ARVIXE non accettata la migrazione e/o registrazione di domini .it ed .eu

Selezione Linq su DataTable

L'utilizzo diretto di Linq su DataTable non è possibile; è tuttavia possibile applicare Linq sulla proprietà DefaultView della DataTable che restituisce l'oggetto DataView associato alla tabella, ovvero la vista personalizzabile di un oggetto DataTable. Ad esempio il codice seguente tralascia le prime 5 righe della tabella ed estrae le successive 15
Dim dt as DataTable = ....
Dim query = From row In dt.DefaultView Skip 5 Take 15

Formato Money in SQL SERVER

Pochi giorni fa ho perso più di una giornata per comprendere e risolvere un problema con la visualizzazione del contenuto di una campo Money in SQL SERVER 2008.

In particolare sul server di sviluppo il delimitatore dei decimali era la "," (virgola) mentre sul server di produzione il "." (punto).

Per cui ad esempio sul server di sviluppo veniva restituita una valuta con il seguente formato "1500,13" mentre sul server di produzione ottenevo "1500.13".

E' da notare che le impostazioni internazionali di Windows erano le stesse così come la lingua e le impostazioni dell'istanza di SQL SERVER.

Dopo aver perso non poche ore nel controllare le differenze tra le istanze di SQL SERVER mi sono accorto che Windows permette di personalizzare la visualizzazione della valuta così come dei numeri. Per scegliere il formato desiderato è sufficiente dal pannello di controllo accedere all' "Orologio e opzioni internazionali"  e quindi selezionare "Paese e lingua". Nelle "Impostazioni aggiuntive" di "Paese e lingua" è possibile modificare il formato di visualizzazione dei numeri, della valuta, dell'ora e della data.

Nulla di più semplice ma occorre saperlo ...