24

impersonare utilizzando i moduli che hanno un sito ASP.NET che deve utilizzare autenticazione basata su form e non autenticazione di Windows per accedere a un ActiveDirectoryMembershipProvider. Il sito deve utilizzare i moduli perché richiedono un modulo di input progettato anziché il popup di autenticazione del browser utilizzato dall'autenticazione di Windows.autenticazione

il sito deve rappresentare l'utente connesso tramite Active Directory per accedere ai file specifici dell'utente.

Tuttavia, il WindowsIdentity.GetCurrent() non è lo stesso del HttpContext.Current.User.Identity anche se il mio web.config contiene:

<authentication mode="Forms"> 
    <forms loginUrl="login.aspx" timeout="480"/> 
</authentication> 
<identity impersonate="true" /> 

non posso usare LoginUser() e la WindowsIdentity.Impersonate() perché ho bisogno di impersonare l'utente AD per ottenere le loro autorizzazioni specifiche , e non so la password dell'utente, perché le forme si prende cura di login.

e 'possibile forse dalle login.aspx.cs, a prendere il System.Web.UI.WebControls.Login.Password, quindi salvare il LoginUser() gettone in una variabile di sessione per WindowsIdentity.Impersonate() dopo? O forse un metodo molto più sicuro di impersonare nel modo giusto?

Sono confuso perché autenticazione basata su form non può automaticamente <identity impersonate="true" />

ho letto questo http://msdn.microsoft.com/en-us/library/ms998351.aspx ma utilizza l'autenticazione di Windows.

+0

Ecco la soluzione che ho usato: ho dato l'accesso IUSER_ ai file, poi verifico ottenere i permessi di ogni file o una cartella tramite DirectorySecurity.GetAccessRules(). Se il file 'FileSystemAccessRule.Value ==" DOMAIN \\ "+ Page.User.Identity.Name' nelle regole di accesso, allora aggiungo quel file o cartella a un elenco. Infine visualizzo l'elenco dei file. Quindi, invece di impersonare, do l'IUSR_ accesso completo e controllo le autorizzazioni manualmente sulle cose a cui ho bisogno che l'utente acceda. – Robert

risposta

19

rappresentazione di un utente utilizzando i moduli di autenticazione può essere fatto. Il seguente codice funziona.

Il Visual Studio Magazine article indicato da Robert è una risorsa eccellente. Ci sono alcuni problemi con il codice di esempio nell'articolo, quindi ho incluso del codice funzionante di seguito.

Nota: se si utilizza Visual Studio, assicurarsi di avviarlo "Esegui come amministratore" per evitare problemi con la rappresentazione del blocco del controllo dell'account utente.

// in your login page (hook up to OnAuthenticate event) 
protected void LoginControl_Authenticate(object sender, AuthenticateEventArgs e) 
{ 
    int token; 
    // replace "YOURDOMAIN" with your actual domain name 
    e.Authenticated = LogonUser(LoginUser.UserName,"YOURDOMAIN",LoginUser.Password,8,0,out token); 
    if (e.Authenticated) { 
     Session.Add("principal", new WindowsPrincipal(new WindowsIdentity(new IntPtr(token)))); 
    } 
} 

[DllImport("advapi32.dll", SetLastError = true)] 
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, 
    int dwLogonType, int dwLogonProvider, out int TokenHandle); 


// in global.asax.cs 
void Application_PreRequestHandlerExecute(object send, EventArgs e) 
{ 
    if (Thread.CurrentPrincipal.Identity.IsAuthenticated == true && HttpContext.Current.Session != null) { 
     WindowsPrincipal windowsPrincipal = (WindowsPrincipal)Session["principal"]; 
     Session["principal"] = (GenericPrincipal)Thread.CurrentPrincipal; 
     Thread.CurrentPrincipal = windowsPrincipal; 
     HttpContext.Current.User = windowsPrincipal; 
     HttpContext.Current.Items["identity"] = ((WindowsIdentity)windowsPrincipal.Identity).Impersonate(); 
    } 
} 

// in global.asax.cs 
void Application_PostRequestHandlerExecute(object send, EventArgs e) 
{ 
    if (HttpContext.Current.Session != null && Session["principal"] as GenericPrincipal != null) { 
     GenericPrincipal genericPrincipal = (GenericPrincipal)Session["principal"]; 
     Session["principal"] = (WindowsPrincipal)Thread.CurrentPrincipal; 
     Thread.CurrentPrincipal = genericPrincipal; 
     HttpContext.Current.User = genericPrincipal; 
     ((WindowsImpersonationContext)HttpContext.Current.Items["identity"]).Undo(); 
    } 
} 

// test that impersonation is working (add this and an Asp:Label to a test page) 
protected void Page_Load(object sender, EventArgs e) 
{ 
    try { 
     // replace YOURSERVER and YOURDB with your actual server and database names 
     string connstring = "data source=YOURSERVER;initial catalog=YOURDB;integrated security=True"; 
     using (SqlConnection conn = new SqlConnection(connstring)) { 
      conn.Open(); 
      SqlCommand cmd = new SqlCommand("SELECT SUSER_NAME()", conn); 
      using (SqlDataReader rdr = cmd.ExecuteReader()) { 
       rdr.Read(); 
       Label1.Text = "SUSER_NAME() = " + rdr.GetString(0); 
      } 
     } 
    } 
    catch { 
    } 
} 

Aggiornamento:

Si dovrebbe anche gestire Application_EndRequest, perché chiamate come Response.End() saranno bypassare Application_PostRequestHandlerExecute.

Un altro problema è che WindowsIdentity può ottenere la raccolta dei dati inutili, pertanto è necessario creare un nuovo WindowsIdentity e WindowsPrincipal dal token di accesso su ogni richiesta.

Update2:

non sono sicuro perché questo è sempre downvoted, perché funziona. Ho aggiunto la firma pinvoke e un codice di prova. Ancora una volta, avviare Visual Studio utilizzando "Esegui come amministratore". Google come farlo se non sai come.

+0

FWIW, (Sono la domanda OP) Ho messo su questa risposta e ho cambiato la risposta corretta. – Robert

+0

Questo approccio non ha funzionato per MVC nei miei test, ma sono riuscito a farlo ignorando BeginExecute ed EndExecute da System.Web.Mvc.Controller. Il problema di questo approccio è che ho bisogno di metterlo in na BaseController e cambiare tutto il controller esistente per ereditare da questo BaseController – Luty

+0

Sto usando anche MVC. Ho dovuto commentare la sessione ["principal"] = (GenericPrincipal) Thread.CurrentPrincipal; linea perché non è stato possibile convertire un web.PrincipalRole in un GenericPrincipal. Non importava però perché avevo solo bisogno di impersonare un utente durante la connessione al database, quindi non avevo bisogno di archiviare l'utente rappresentato per l'uso in tutto il sito. Il che significa che anche io non ho inserito nulla nel file global.asax.cs l'ho appena incluso nella mia classe di db. – Kevin

0

Se gli utenti utilizzano IE, è possibile attivare la protezione integrata per il sito Web e gli utenti verranno autenticati automaticamente (nessuna finestra di accesso, nessuna pagina di accesso). La tua imitazione funzionerà quindi. Se devi scegliere come target altri browser, questo potrebbe non funzionare (probabilmente all'utente verrà presentata una finestra di accesso).

tua rappresentazione attuale non funzionerà mai perché i vostri utenti accedono utilizzando un account diverso dal loro account di dominio. Non puoi pretendere che il sito impersonifichi un utente che non ha fornito le sue credenziali. Ciò andrebbe contro i principi di sicurezza di base.

+2

È una extranet, quindi gli utenti accedono ai file interni utilizzando account AD dall'esterno della LAN. Quando si utilizza un ActiveDirectoryMembershipProvider, gli utenti effettuano l'accesso utilizzando il proprio account di dominio. L'archivio utente effettivo è AD, è possibile accedere utilizzando l'autenticazione Moduli o Windows, ma non può accedere ai file quando si utilizza Moduli, solo quando si utilizza Windows poiché Form utilizza l'account IUSR_ *. – Robert

0

Abbiamo avuto lo stesso problema di recente, il cliente voleva che gli utenti possano accedere tramite l'account AD e quindi questa credenziale deve essere utilizzata per accedere a Analysis Service e tutti gli altri database . Lo hanno voluto in questo modo perché hanno implementato un sistema di auditing e tutti gli accessi devono essere effettuati dall'account loggato corrente.

Abbiamo provato l'autenticazione basata su form e l'API LogonUser() Win32 per impersonare la parte, ha funzionato ma ci chiede anche la password dell'utente come testo normale. In seguito, abbiamo deciso di utilizzare l'autenticazione di Windows, ci fa risparmiare molto tempo (non più autenticazione AD, impersonare manualmente). Naturalmente, non c'era nemmeno una pagina di accesso di fantasia.

-6

In Visual Studio installare NuGet Aprire la soluzione

Poi nel pacchetto console run-Install Package 51Degrees.mobi

Sarà quindi aggiungere 51Degrees al tuo sito web. È quindi possibile modificare 51Degrees.mobi.config nei dati dell'app per rimuovere la sezione di reindirizzamento.

A questo punto avere fino a data funzionalità del browser

-1

Per ogni evenienza, e un po 'tardi, ho trovato qualcosa che funziona per me ed è davvero semplice, ma, naturalmente, è solo a scopo di test ...

Basta impostare un cookie con il tuo username.

//Login button. You can give whatever input to the form 
protected void Login_Click(object sender, EventArgs e) 
{ 
    FormsAuthentication.SetAuthCookie("your_username", createPersistentCookie: true); 
    Response.Redirect("~/"); 
} 

Qualsiasi commento accettata ...

+0

Questa domanda riguarda come ottenere 'WindowsIdentity.Impersonate()' per funzionare. Non vedo come questa risposta tenti di rispondere a questa domanda – KyleMit