Confessions of a Dangerous Mind

Brain.FlushBuffer()
posts - 176, comments - 234, trackbacks - 93

Single Sign-On con ASP.net 2.0 e Membership API

Spesso mi è capitato di imbattermi nel problema di avere più applicazioni web che permettano agli stessi utenti di autenticarsi e di lavorare liberamente al loro interno. Ancora più spesso mi sono imbattuto nella difficoltà di realizzare tale obiettivo, soprattutto per via del fatto che ogni applicazione web implementava l'autenticazione a modo suo, con risultati spesso discutibili dal punto di vista della sicurezza.

Molte volte ci siamo trovati a valutare come sistema di Single Sign-On l'autenticazione su Active Directory, ma questa è fattibile soprattutto in ambienti intranet e non in un ambiente internet, dove magari i nostri utenti possono addirittura auto-registrarsi.

L'eleganza della Membership API permette di sorpassare ogni problema, raggiungendo l'obiettivo di condividere le credenziali dell'utente attraverso più applicazioni web. Ovvero si potrà, ad esempio, creare un'applicazione web dedicata alle vendite e, successivamente, un'applicazione web dedicata alla reportistica. Queste due applicazioni potranno condividere le informazioni relative agli utenti ed ai loro ruoli, in modo da uniformare la gestione della sicurezza.

Ora, come implementare una feature così appetibile? Beh, vi assicuro che è più facile farlo che spiegarlo ...

Come prima cosa, dobbiamo evitare di usare il "classico" database SQL express che il buon vecchi VS2005 crea automaticamente per noi. Piuttosto, creiamo un database che fungerà da repository condiviso di credenziali (Shared Credential Repository, SCR), mediante il tool aspnet_regsql.exe, che possiamo trovare nella directory %WINDOWS%\Microsoft.NET\Framework\v2.0.50727. Lasciando come <default> la selezione del database, creeremo un DB di nome ASPNETDB nel nostro server SQL che potrà essere utilizzato per i nostri fini. A questo punto, visto che siamo nei paraggi, diamo un'occhiatina al file Machine.config che si trova nella sottodirectory CONFIG. Al suo interno possiamo trovare le seguenti parti "interessanti":

<connectionStrings>
    <add 
name="LocalSqlServer" 
    
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" />
<
/connectionStrings>
...snip...
<membership>
    <providers>
        <add 
name="AspNetSqlMembershipProvider" 
        
type="System.Web.Security.SqlMembershipProvider, System.Web, Version=2.0.0.0, Culture=neutral, 
        
PublicKeyToken=b03f5f7f11d50a3a" 
        
connectionStringName="LocalSqlServer" 
        
enablePasswordRetrieval="false" 
        
enablePasswordReset="true" 
        
requiresQuestionAndAnswer="true" 
        
applicationName="/" 
        
requiresUniqueEmail="false" 
        
passwordFormat="Hashed" 
        
maxInvalidPasswordAttempts="5" 
        
minRequiredPasswordLength="7" 
        
minRequiredNonalphanumericCharacters="1" 
        
passwordAttemptWindow="10" 
        
passwordStrengthRegularExpression="" />
    <
/providers>
<
/membership>
...snip...

Il punto su cui ragionare, in vista delle nostre applicazioni, è la ConnectionString "LocalSqlServer" e come questa viene utilizzata dal provider AspNetSqlMembershipProvider. Noi vogliamo mantenere questo provider senza apportare modifiche in ciascuna applicazione web, in modo che modificando il comportamento della membership all'interno del Machine.config, tutte le applicazioni installate sul nostro server beneficino del comportamento. Del resto è anche una questione di coerenza nelle policies di sicurezza, giusto? Preso atto di questo, creiamo una applicazione web di nome SalesApp, aggiungiamo un paio di pagine Login.aspx e Register.aspx nelle quali aggiungiamo, rispettivamente, un controllo Login ed un controllo User Creation Wizard. Nella pagina Default.aspx aggiungiamo un controllo LoginStatus e un controllo LoginName. Il pezzo forte di tutto questo, comunque è il file Web.config, che deve essere così composto:

<?xml version="1.0"?>
<configuration>
  <appSettings
/>
  <connectionStrings>
    <
clear/>
    
<!--configure Shared Credential Repository-->
    
<add name="LocalSqlServer" connectionString="SERVER=MYSERVER;DATABASE=ASPNETDB;UID=sa;PWD=password" providerName="System.Data.SqlClient" />
  <
/connectionStrings>
  <system.web>
    <compilation 
debug="false" strict="false" explicit="true" />
    <authentication 
mode="Forms">
      
<!--configure authentication element: name, path, protection-->
      
<forms name=".SHAREDTOKEN" loginUrl="login.aspx" protection="All" 
              
timeout="30"
              
path="/"
              
requireSSL="false"
              
slidingExpiration="true"
              
cookieless="UseCookies"/>
    <
/authentication>
    
<!--configure machineKey. Must be the same for each application!!-->
    
<machineKey validationKey="95E209A1882F59B1585FD2691BB0AEF28E8158C1CD26EADA9B2B3CF8821F2D3D39347B487F72D94E438E4EE510A730FE979A3E79D18A5DB453FE87979D25AACC" decryptionKey="B753AE2B2CEAFD2BA6B938744ECD8550ECE5F6BB51506E43" validation="SHA1" />
    
<!--deny access to unauthenticated users-->
    
<authorization>
      <deny 
users="?" />
    <
/authorization>
  <
/system.web>
<
/configuration>

Esaminiamo, dunque, questo file, fondamentale per il buon funzionamento della nostra "Shared-Membership"; ho modificato la stringa di connessione LocalSqlServer, in modo da farla puntare allo Shared Credential Repository creato in precedenza. Nell'elemento authentication si può vedere l'attibuto mode, impostato a Forms, ed all'interno, l'elemento forms configurato con un name, un path ed una protection ben definite. Dobbiamo fare attenzione a questi valori, perchè dovranno essere uguali in ogni applicazione che vogliamo far entrare nella nostra Shared Membership (nel club, per intenderci...). Oltre a questa impostazione, un altro elemento deve essere identico in tutte le nostre web application, ed è l'elemento machineKey. I tre attributi validationKey, decryptionKey e validation devono essere identici sempre per tutte le web app del club. Per generare valori validi riferitevi a MachineKey Generator.

A questo punto, il gioco è fatto! Per creare il primo utente, rimuovete il deny users="?" in modo da poter navigare la pagina register.aspx e create l'utente. Questo verrà creato all'interno del repository condiviso, e sarà a disposizione di tutte le applicazioni che utilizzeranno questo pattern di autenticazione condivisa. Ripristinando il deny users, la cosa simpatica è che se create un'applicazione di nome ReportApp, copiate il file web.config dalla SalesApp alla ReportApp, create un link che dalla SalesApp punti alla ReportApp e vi autenticate nella SalesApp, una volta giunti alla ReportApp, questa vi "riconoscerà" e nella pagina di default comparirà il nome del vostro utente. Stiamo quindi lavorando con un utente in un'applicazione web, essendoci autenticati presso un'altra applicazione. Estremizzando, potremmo creare un'applicazione per l'autenticazione che rinvia ad altre applicazioni concrete che implementino le funzionalità desiderate. A questo indirizzo potete trovare un semplice progetto con due applicazioni web per testare questa feature estremamente potente di ASP.net 2.0.

Nel caso in cui vogliate riportare le impostazioni del provider nel Web.Config, fate attenzione al nome dell'applicazione! Se volete condividere Membership Ruoli e Profili tra le applicazioni, dovete impostare l'attributo name allo stesso valore per ogni applicazione!

Happy authenticating!

 

Print | posted on mercoledì 7 giugno 2006 20:15 | Filed Under [ Tutorials ]

Feedback

Gravatar

# re: Single Sign-On con ASP.net 2.0 e Membership API

Ciao Francesco,
bisogna modificare la connection string, proprio così.
E poi, puoi continuare ad usare l'ASP.net COnfigurator... lo faccio anche io.
Considera, comunque, che per un sito in produzione sarebbe meglio implementare una gestione di utenti e ruoli...
Un saluto!
17/06/2006 20:57 | Davide Senatore
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET