In questa paginaObiettiviIl modulo consente di: | • | Creare un'applicazione Web che utilizzi l'autenticazione basata su moduli per autenticare gli utenti rispetto ad Active Directory. | | • | Ottenere un elenco di gruppi e liste di distribuzione a cui appartiene un utente autenticato in Active Directory | | • | Creare un oggetto GenericPrincipal che sia associato alla richiesta Web dell'utente utilizzando la proprietà HttpContext.Current.User. |
Ambito di applicazioneLe informazioni contenute in questo modulo sono valide per i seguenti prodotti e tecnologie: | • | Microsoft Windows® XP o Windows 2000 Server con Service Pack 3 e sistemi operativi successivi | | • | Active Directory | | • | Microsoft .NET Framework versione 1.0 con Service Pack 2 e versioni successive | | • | Microsoft Visual Studio® 1.0 .NET e versioni successive | | • | Microsoft Visual C#® .NET | | • | Microsoft SQL Server 2000 con Service Pack 2 e versioni successive |
Utilizzo del moduloPer trarre il massimo vantaggio dal modulo: | • | È necessario aver acquisito esperienza nell'utilizzo di Visual C# .NET e Visual Studio .NET. | | • | È necessario aver acquisito esperienza nello sviluppo di applicazioni Web mediante l'utilizzo di ASP.NET. | | • | È necessario aver acquisito esperienza nell'utilizzo di Active Directory. | | • | È necessario accedere a un'istanza di Active Directory che possa essere impie | | • | Leggere il modulo 3 di questa guida "Autenticazione e autorizzazione". In tale modulo sono riportati i dettagli relativi ad alcuni meccanismi di autenticazione e viene illustrata la protezione basata su ruoli di .NET. | | • | Leggere il modulo 8 di questa guida, "Protezione di ASP.NET". Nel modulo sono riportate informazioni dettagliate sull'autenticazione basata sui moduli Web per ASP.NET. |
RiepilogoL'autenticazione basata su moduli di ASP.NET consente agli utenti di identificarsi immettendo le credenziali (nome utente e password) in un modulo Web. Quando l'applicazione Web riceve le credenziali, può autenticare l'utente confrontando la combinazione delle credenziali con un'origine dati. In questo modulo viene descritta la procedura di autenticazione degli utenti rispetto al servizio Microsoft® Active Directory® tramite il protocollo LDAP (Lightweight Directory Access Protocol). Viene inoltre descritta la procedura per il recupero di un elenco dei gruppi di protezione e delle liste di distribuzione a cui appartiene l'utente e per la configurazione di un oggetto GenericPrincipal da utilizzare con l'autorizzazione basata su ruoli di .NET. Creazione di un'applicazione Web con una pagina di accessoQuesta procedura consente di creare una semplice applicazione Web in Visual C#, composta da una pagina di accesso, in cui l'utente immette il nome utente e la password, e da una pagina predefinita, in cui vengono visualizzate le informazioni sul nome di identità e sul gruppo di appartenenza associate alla richiesta Web corrente. | • | Per creare un'applicazione Web con una pagina di accesso 1. | Avviare Visual Studio .NET e creare una nuova applicazione Web ASP.NET in Visual C# denominata FormsAuthAD. | 2. | Utilizzare Esplora soluzioni per rinominare WebForm1.aspx come Logon.aspx. | 3. | Aggiungere un nuovo riferimento all'assembly in System.DirectoryServices.dll. In tal modo verrà consentito l'accesso allo spazio dei nomi System.DirectoryServices contenente i tipi gestiti per facilitare le query e la manipolazione della Active Directory. | 4. | Aggiungere a Logon.aspx i controlli elencati nella tabella 1 per creare un semplice modulo di accesso. Tabella 1: Controlli di Logon.aspx Etichetta | Nome dominio: | - | Etichetta | Nome utente: | - | Etichetta | Password | - | Casella di testo | - | txtDomainName | Casella di testo | - | txtUserName | Casella di testo | - | txtPassword | Pulsante | Accesso | btnLogon | Etichetta | | lblError |
| 5. | Impostare la proprietà TextMode di txtPassword su Password. | 6. | In Esplora soluzioni fare clic con il pulsante destro del mouse su FormsAuthAd, selezionare Aggiungi, quindi fare clic su Aggiungi Web Form. | 7. | Nel campo Nome digitare default.aspx, quindi fare clic su Apri. | 8. | In Esplora soluzioni fare clic con il pulsante destro del mouse su default.aspx, quindi fare clic su Imposta come pagina iniziale. | 9. | Fare doppio clic su default.aspx per visualizzare il gestore eventi di caricamento della pagina. | 10. | Aggiungere il codice riportato di seguito al gestore eventi per visualizzare il nome di identità associato alla richiesta Web corrente.
Response.Write( HttpContext.Current.User.Identity.Name );
|
|
Configurazione dell'applicazione Web per l'autenticazione basata su moduliQuesta procedura consente di modificare il file web.config in modo da configurare l'applicazione per l'autenticazione basata su moduli. | • | Per configurare l'applicazione Web per l'autenticazione basata su moduli 1. | Utilizzare Esplora soluzioni per aprire il file web.config. | 2. | Individuare l'elemento <authentication> e modificare l'attributo mode impostandolo su Forms. | 3. | Aggiungere l'elemento <forms> che segue come figlio dell'elemento di autenticazione e impostare gli attributi loginUrl, name, timeout e path nel modo seguente:
<authentication mode="Forms">
<forms loginUrl="logon.aspx" name="adAuthCookie" timeout="60" path="/">
</forms>
</authentication>
| 4. | Aggiungere l'elemento <authorization> riportato di seguito sotto l'elemento <authentication>. In questo modo, l'accesso all'applicazione verrà consentito solo agli utenti autenticati. L'attributo loginUrl dell'elemento <authentication>, definito in precedenza, reindirizzerà le richieste non autenticate alla pagina logon.aspx.
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
| 5. | Salvare il file web.config. | 6. | Avviare lo snap-in MMC (Microsoft Management Console) di IIS. | 7. | Fare clic con il pulsante destro del mouse sulla directory virtuale dell'applicazione, quindi selezionare Proprietà. | 8. | Fare clic sulla scheda Protezione directory, quindi sul pulsante Modifica nel gruppo Controllo autenticazione e accesso anonimo. | 9. | Selezionare la casella di controllo Accesso anonimo e deselezionare la casella di controllo Abilita controllo delle password. | 10. | Poiché l'account anonimo predefinito IUSR_MACHINE non dispone dell'autorizzazione per accedere ad Active Directory, è necessario creare un nuovo account con privilegi minimi e immettere i relativi dettagli nella finestra di dialogo Metodi di autenticazione. | 11. | Fare clic su OK, quindi di nuovo su OK per chiudere la finestra di dialogo Proprietà. | 12. | Tornare a Visual Studio .NET, aggiungere un elemento <identity> sotto l'elemento <authorization> nel file web.config e impostare l'attributo <impersonate> su true. In questo modo ASP.NET rappresenterà l'account anonimo specificato in precedenza.
<identity impersonate="true" />
In base a tale configurazione, tutte le richieste inoltrate all'applicazione verranno eseguite nel contesto di protezione dell'account anonimo configurato. L'utente specificherà le credenziali tramite il modulo Web per eseguire l'autenticazione rispetto ad Active Directory, ma l'account utilizzato per accedere ad Active Directory sarà l'account anonimo configurato. |
|
Sviluppo del codice di autenticazione LDAP per individuare l'utente in Active DirectoryQuesta procedura consente di aggiungere una nuova classe di supporto all'applicazione Web per incapsulare il codice LDAP. La classe fornirà inizialmente un metodo IsAuthenticated per convalidare un dominio, un nome utente e una password specificati rispetto a un oggetto utente di Active Directory. | • | Per sviluppare il codice di autenticazione LDAP in modo da individuare l'utente in Active Directory 1. | Aggiungere un nuovo file di classe C# denominato LdapAuthentication.cs. | 2. | Aggiungere un riferimento all'assembly System.DirectoryServices.dll. | 3. | Aggiungere le istruzioni using riportate di seguito all'inizio dell'assembly LdapAuthentication.cs.
using System.Text;
using System.Collections;
using System.DirectoryServices;
| 4. | Rinominare lo spazio dei nomi esistente come FormsAuthAD. | 5. | Aggiungere due stringhe private alla classe LdapAuthentication, una per il percorso LDAP ad Active Directory e l'altra per un attributo filtro utilizzato per la ricerca in Active Directory.
private string _path;
private string _filterAttribute;
| 6. | Aggiungere un costruttore pubblico che possa essere utilizzato per inizializzare il percorso di Active Directory.
public LdapAuthentication(string path)
{
_path = path;
}
| 7. | Aggiungere il metodo IsAuthenticated riportato di seguito, che accetta un nome di dominio, un nome utente e una password come parametri e restituisce il valore bool per indicare se all'interno di Active Directory esiste o meno l'utente con una password corrispondente. Il metodo tenta inizialmente di eseguire il binding ad Active Directory utilizzando le credenziali specificate. Se il binding viene eseguito, il metodo utilizza la classe gestita DirectorySearcher per cercare l'oggetto utente specificato. Se individuato, il membro _path viene aggiornato in modo da puntare all'oggetto utente mentre il membro _filterAttribute viene aggiornato con l'attributo del nome comune dell'oggetto utente.
public bool IsAuthenticated(string domain, string username, string pwd)
{
string domainAndUsername = domain + @"\" + username;
DirectoryEntry entry = new DirectoryEntry( _path,
domainAndUsername, pwd);
try
{
// Bind to the native AdsObject to force authentication.
Object obj = entry.NativeObject;
DirectorySearcher search = new DirectorySearcher(entry);
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
SearchResult result = search.FindOne();
if(null == result)
{
return false;
}
// Update the new path to the user in the directory
_path = result.Path;
_filterAttribute = (String)result.Properties["cn"][0];
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message);
}
return true;
}
|
|
Sviluppo del codice di recupero dei gruppi LDAP per individuare il gruppo di appartenenza dell'utenteQuesta procedura consente di estendere la classe LdapAuthentication per fornire un metodo GetGroups che recupererà l'elenco dei gruppi a cui appartiene l'utente corrente. Il metodo GetGroups restituirà l'elenco dei gruppi in formato di stringa separata da barre verticali, come indicato di seguito.
"Group1|Group2|Group3|"
| • | Per sviluppare il codice di recupero dei gruppi LDAP in modo da individuare i gruppi di appartenenza dell'utente 1. | Aggiungere l'implementazione del metodo GetGroups riportata di seguito alla classe LdapAuthentication.
public string GetGroups()
{
DirectorySearcher search = new DirectorySearcher(_path);
search.Filter = "(cn=" + _filterAttribute + ")";
search.PropertiesToLoad.Add("memberOf");
StringBuilder groupNames = new StringBuilder();
try
{
SearchResult result = search.FindOne();
int propertyCount = result.Properties["memberOf"].Count;
String dn;
int equalsIndex, commaIndex;
for( int propertyCounter = 0; propertyCounter < propertyCount;
propertyCounter++)
{
dn = (String)result.Properties["memberOf"][propertyCounter];
equalsIndex = dn.IndexOf("=", 1);
commaIndex = dn.IndexOf(",", 1);
if (-1 == equalsIndex)
{
return null;
}
groupNames.Append(dn.Substring((equalsIndex + 1),
(commaIndex - equalsIndex) - 1));
groupNames.Append("|");
}
}
catch(Exception ex)
{
throw new Exception("Error obtaining group names. " + ex.Message);
}
return groupNames.ToString();
}
|
|
Autenticazione dell'utente e creazione del ticket per l'autenticazione basata su moduliQuesta procedura consente di implementare il gestore eventi btnLogon_Click per autenticare gli utenti. Per gli utenti autenticati verrà creato quindi un ticket di autenticazione basata su moduli contenente l'elenco dei gruppi dell'utente. In seguito l'utente dovrà essere reindirizzato alla pagina richiesta prima dell'invio alla pagina di accesso. | • | Per autenticare l'utente e creare un ticket per l'autenticazione basata su moduli 1. | Tornare al modulo Logon.aspx e fare doppio clic sul pulsante Accedi per creare un gestore eventi btnLogon_Click vuoto. | 2. | Aggiungere all'inizio del file la seguente istruzione using sotto le istruzioni using esistenti. In questo modo verrà abilitato l'accesso ai metodi FormsAuthentication.
using System.Web.Security;
| 3. | Aggiungere il codice per la creazione di una nuova istanza della classe LdapAuthentication inizializzata in modo da fare riferimento all'autenticazione LDAP di Active Directory, come indicato di seguito. È importante ricordarsi di modificare il percorso in modo che faccia riferimento al server Active Directory.
// Path to you LDAP directory server.
// Contact your network administrator to obtain a valid path.
string adPath = "LDAP://yourCompanyName.com/DC=yourCompanyName,DC=com";
LdapAuthentication adAuth = new LdapAuthentication(adPath);
| 4. | Aggiungere il codice riportato di seguito per eseguire le seguenti operazioni: 1. | Autenticare il chiamante rispetto ad Active Directory. | 2. | Recuperare l'elenco dei gruppi a cui appartiene l'utente. | 3. | Creare un ticket di tipo FormsAuthenticationTicket contenente l'elenco dei gruppi. | 4. | Crittografare il ticket. | 5. | Creare un nuovo cookie con il ticket crittografato. | 6. | Aggiungere il cookie all'elenco dei cookie restituito al browser dell'utente.
try
{
if(true == adAuth.IsAuthenticated(txtDomainName.Text,
txtUserName.Text,
txtPassword.Text))
{
// Retrieve the user's groups
string groups = adAuth.GetGroups();
// Create the authetication ticket
FormsAuthenticationTicket authTicket =
new FormsAuthenticationTicket(1, // version
txtUserName.Text,
DateTime.Now,
DateTime.Now.AddMinutes(60),
false, groups);
// Now encrypt the ticket.
string encryptedTicket = FormsAuthentication.Encrypt(authTicket);
// Create a cookie and add the encrypted ticket to the
// cookie as data.
HttpCookie authCookie =
new HttpCookie(FormsAuthentication.FormsCookieName,
encryptedTicket);
// Add the cookie to the outgoing cookies collection.
Response.Cookies.Add(authCookie);
// Redirect the user to the originally requested page
Response.Redirect(
FormsAuthentication.GetRedirectUrl(txtUserName.Text,
false));
}
else
{
lblError.Text =
"Authentication failed, check username and password.";
}
}
catch(Exception ex)
{
lblError.Text = "Error authenticating. " + ex.Message;
}
|
|
|
Implementazione di un gestore di richieste di autenticazione per creare un oggetto GenericPrincipalQuesta procedura consente di implementare il gestore eventi Application_AuthenticateRequest all'interno di global.asax e di creare un oggetto GenericPrincipal per l'utente autenticato corrente. Tale oggetto includerà l'elenco dei gruppi a cui appartiene l'utente, recuperato dal ticket FormsAuthenticationTicket contenuto nel cookie di autenticazione. Infine, l'oggetto GenericPrincipal verrà associato all'oggetto HttpContext corrente creato per ciascuna richiesta Web. | • | Per implementare un gestore di richieste di autenticazione per creare un oggetto GenericPricipal 1. | Utilizzare Esplora soluzioni per aprire global.asax.cs. | 2. | Aggiungere all'inizio del file le istruzioni using riportate di seguito.
using System.Web.Security;
using System.Security.Principal;
| 3. | Individuare il gestore eventi Application_AuthenticateRequest e aggiungere il codice riportato di seguito. In tal modo, dalla raccolta di cookie passata con la richiesta, si ottiene il cookie con il ticket crittografato FormsAuthenticationTicket.
// Extract the forms authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
if(null == authCookie)
{
// There is no authentication cookie.
return;
}
| 4. | Aggiungere il codice riportato di seguito per estrarre il ticket FormsAuthenticationTicket dal cookie e decifrarlo.
FormsAuthenticationTicket authTicket = null;
try
{
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
}
catch(Exception ex)
{
// Log exception details (omitted for simplicity)
return;
}
if (null == authTicket)
{
// Cookie failed to decrypt.
return;
}
| 5. | Aggiungere il codice riportato di seguito per analizzare l'elenco dei nomi di gruppi separati da barre verticali, associato al ticket quando l'utente è stato autenticato in origine.
// When the ticket was created, the UserData property was assigned a
// pipe delimited string of group names.
String[] groups = authTicket.UserData.Split(new char[]{'|'});
| 6. | Aggiungere il codice riportato di seguito per creare un oggetto GenericIdentity con il nome utente ottenuto dal nome del ticket e un oggetto GenericPrincipal che contenga tale identità insieme all'elenco di gruppi dell'utente.
// Create an Identity object
GenericIdentity id = new GenericIdentity(authTicket.Name,
"LdapAuthentication");
// This principal will flow throughout the request.
GenericPrincipal principal = new GenericPrincipal(id, groups);
// Attach the new principal object to the current HttpContext object
Context.User = principal;
|
|
Test dell'applicazioneQuesta procedura consente di utilizzare l'applicazione Web per richiedere la pagina default.aspx. L'autore della richiesta verrà reindirizzato alla pagina di accesso per l'autenticazione. Se questa avviene correttamente, il browser verrà reindirizzato alla pagina default.aspx richiesta in origine. In questa pagina verrà estratto e visualizzato l'elenco dei gruppi a cui appartiene l'utente autenticato, ottenuto dall'oggetto GenericPrincipal associato alla richiesta corrente dal processo di autenticazione. | • | Per eseguire il test dell'applicazione 1. | Scegliere Genera soluzione dal menu Genera. | 2. | In Esplora soluzioni fare clic con il pulsante destro del mouse su default.aspx, quindi scegliere Visualizza nel browser. | 3. | Immettere un nome di dominio, un nome utente e una password validi, quindi fare clic su Accedi. | 4. | Se l'autenticazione viene eseguita correttamente, l'utente verrà reindirizzato di nuovo alla pagina default.aspx. Nel codice di questa pagina deve essere visualizzato il nome utente dell'utente autenticato. Per visualizzare l'elenco dei gruppi a cui appartiene l'utente autenticato, aggiungere il codice riportato di seguito alla fine del gestore eventi Application_AuthenticateRequest nel file global.aspx.cs.
Response.Write("Groups: " + authTicket.UserData + "<br>");
|
|
| |