24

Mam witrynę ASP.NET, która musi korzystać z uwierzytelniania za pomocą formularzy, a nie z uwierzytelniania systemu Windows, aby uzyskać dostęp do ActiveDirectoryMembershipProvider. Witryna musi używać formularzy, ponieważ potrzebują one zaprojektowanego formularza wejściowego zamiast wyskakującego okna uwierzytelniania przeglądarki, którego używa uwierzytelnianie systemu Windows.Personifikowanie przy użyciu uwierzytelniania za pomocą formularzy

Witryna musi podszywać się pod użytkownika zalogowanego za pośrednictwem usługi Active Directory, aby uzyskać dostęp do plików określonych przez użytkownika.

Jednak WindowsIdentity.GetCurrent() nie jest taka sama jak HttpContext.Current.User.Identity chociaż moim web.config zawiera:

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

Nie mogę korzystać LoginUser() a WindowsIdentity.Impersonate() bo muszę podawać się jako użytkownik AD, aby uzyskać ich konkretne uprawnienia i nie wiem, hasło użytkownika, ponieważ formularze dba o zalogowanie się.

Czy to możliwe, być może z login.aspx.cs, aby wziąć System.Web.UI.WebControls.Login.Password, a następnie zapisać LoginUser() żeton w zmiennej sesji dla WindowsIdentity.Impersonate() później? A może o wiele bezpieczniejsza metoda podszywania się pod właściwy sposób?

Jestem mylić dlaczego Forms uwierzytelniania nie może automatycznie <identity impersonate="true" />

Czytałem ten http://msdn.microsoft.com/en-us/library/ms998351.aspx ale używa uwierzytelniania systemu Windows.

+0

Oto obejście użyłem: Dałem dostęp IUSER_ do plików, a następnie sprawdzić, zdobyć uprawnienia każdego pliku lub folderu przez DirectorySecurity.GetAccessRules(). Jeśli "FileSystemAccessRule.Value ==" DOMAIN \\ "+ Page.User.Identity.Name" w regułach dostępu, dodaję ten plik lub folder do listy. Wreszcie wyświetlam listę plików. Więc zamiast podszywać się, daję IUSR_ pełny dostęp i ręcznie sprawdzam uprawnienia do rzeczy, których potrzebuję, aby ten użytkownik miał dostęp. – Robert

Odpowiedz

19

podszywanie się pod użytkownika przy użyciu uwierzytelniania formularzy można zrobić. Poniższy kod działa.

Wymieniony przez Roberta numer Visual Studio Magazine article jest doskonałym źródłem informacji. Występują pewne problemy z przykładowym kodem w artykule, więc dodałem poniżej działający kod.

Uwaga: Jeśli używasz programu Visual Studio, uruchom go jako "Uruchom jako Administrator", aby uniknąć problemów związanych z podszywaniem się pod UAC.

// 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 { 
    } 
} 

Aktualizacja:

Należy również obsługiwać Application_EndRequest, ponieważ rozmowy jak Response.End() ominie Application_PostRequestHandlerExecute.

Inną kwestią jest to, że WindowsIdentity może zbierać śmieci, więc powinieneś utworzyć nowe WindowsIdentity i WindowsPrincipal z tokenu logowania na każde żądanie.

Update2:

Nie jestem pewien, dlaczego to jest uzyskiwanie downvoted, ponieważ działa. Dodałem podpis Pinvoke i trochę kodu testowego. Ponownie uruchom Visual Studio, używając "Uruchom jako Administrator". Google, jak to zrobić, jeśli nie wiesz jak.

+0

FWIW, (jestem pytanie OP) Podniosłem tę odpowiedź i zmieniłem ją na poprawną odpowiedź. – Robert

+0

To podejście nie działało dla MVC w moich testach, ale udało mi się nadpisać BeginExecute i EndExecute z System.Web.Mvc.Controller. Problem z tym podejściem polega na tym, że muszę go umieścić na BaseController i zmienić cały istniejący kontroler, aby dziedziczył z tego BaseController'a – Luty

+0

Używam również MVC. Musiałem skomentować Session ["principal"] = (GenericPrincipal) Thread.CurrentPrincipal; linii, ponieważ nie może konwertować web.PrincipalRole na GenericPrincipal. Nie miało to jednak większego znaczenia, ponieważ musiałem podszywać się pod użytkownika tylko wtedy, gdy łączyłem się z bazą danych, więc nie musiałem przechowywać podszytego użytkownika do użytku w całej witrynie. Co oznacza, że ​​również nie wstawiłem niczego do pliku global.asax.cs Właśnie zawarłem to w mojej klasie db. – Kevin

0

Jeśli Twoi użytkownicy używają IE, możesz włączyć zintegrowane zabezpieczenia witryny, a Twoi użytkownicy zostaną uwierzytelnieni po cichu (bez okna logowania, bez strony logowania). Twoje podszywanie się będzie wtedy działało. Jeśli chcesz kierować reklamy na inne przeglądarki, może to nie działać (prawdopodobnie zostanie wyświetlone okno dialogowe logowania).

Twoje obecne podszywanie się nigdy nie zadziała, ponieważ Twoi użytkownicy logują się przy użyciu konta innego niż ich konto domeny. Nie możesz oczekiwać, że witryna podszyje się pod użytkownika, który nie podał swoich danych uwierzytelniających. Byłoby to sprzeczne z podstawowymi zasadami zabezpieczeń.

+2

To ekstranet, więc użytkownicy uzyskują dostęp do wewnętrznych plików za pomocą kont AD spoza sieci LAN. Podczas korzystania z usługi ActiveDirectoryMembershipProvider użytkownicy logują się przy użyciu swojego konta domeny. Rzeczywisty magazyn użytkowników to AD, mogą oni logować się z powodzeniem za pomocą uwierzytelniania formularzy lub systemu Windows, ale nie mogą uzyskać dostępu do plików podczas korzystania z formularzy, tylko podczas korzystania z systemu Windows, ponieważ formularze używają konta IUSR_ *. – Robert

0

Mamy ten sam problem niedawno, klient chciał, aby jego użytkownicy mogli zalogować się za pomocą konta AD, a następnie to poświadczenie musi zostać użyte do uzyskania dostępu do usługi Analysis Service, jak również wszystkich innych baz danych . Chcieli tego w ten sposób, ponieważ wdrożyli system audytu, a dostęp do niego musi być realizowany przez bieżące zalogowane konto.

Próbowaliśmy uwierzytelniania Forms i Win32 LogonUser() API podszywania się pod część, zadziałało, ale prosi również o podanie hasła użytkownika jako zwykłego tekstu. Później zdecydowaliśmy się na korzystanie z uwierzytelniania systemu Windows, oszczędzamy mnóstwo czasu (nie trzeba już uwierzytelniania AD, personifikować ręcznie). Oczywiście nie było też żadnej wymyślnej strony logowania.

-6

W Visual Studio zainstalować Nuget Otwórz rozwiązanie

Następnie w biegu konsoli pakiet Install-Package 51Degrees.mobi

Będzie on następnie dodać 51Degrees na swojej stronie. Następnie możesz edytować plik 51Degrees.mobi.config w swojej aplikacji, aby usunąć sekcję przekierowania.

będą mieć teraz do możliwości przeglądarki data

-1

Na wszelki wypadek, a trochę późno, znalazłem coś, co działa dla mnie i to bardzo proste, ale jest oczywiście tylko w celach testowych ...

Wystarczy ustawić ciasteczko z nazwą użytkownika.

//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("~/"); 
} 

Wszelkie komentarze zaakceptowanych ...

+0

To pytanie dotyczy sposobu działania 'WindowsIdentity.Impersonate()'. Nie widzę, jak ta odpowiedź próbuje odpowiedzieć na to pytanie – KyleMit