Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impersonate using Forms Authentication

Tags:

I have an ASP.NET site that must use Forms Authentication and not Windows Authentication to access a ActiveDirectoryMembershipProvider. The site must use forms because they need a designed input form instead of the browser authentication popup that Windows authentication uses.

The site needs to impersonate the user logged in via Active Directory to access user specific files.

However, the WindowsIdentity.GetCurrent() is not the same as the HttpContext.Current.User.Identity although my web.config contains:

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

I cannot use LoginUser() and the WindowsIdentity.Impersonate() because I need to impersonate as the AD user to get their specific permissions, and I don't know the user's password because Forms takes care of logging in.

Is it possible maybe from the login.aspx.cs, to take the System.Web.UI.WebControls.Login.Password, then save the LoginUser() token in a session variable for WindowsIdentity.Impersonate() later? Or maybe a much more secure method of Impersonating the right way?

I'm confused why Forms authentication can't automatically <identity impersonate="true" />

I've read this http://msdn.microsoft.com/en-us/library/ms998351.aspx but it uses Windows Authentication.

like image 487
Robert Avatar asked Jun 30 '09 21:06

Robert


People also ask

What is impersonation in authentication?

Impersonation is the process of executing code in the context of another user identity. By default, all ASP.NET code is executed using a fixed machine-specific account. To execute code using another identity we can use the built-in impersonation capabilities of ASP.NET.

What is Windows authentication impersonation?

In a Windows environment, after a user authenticates, the authenticating application can impersonate that user's impersonation. Impersonation is implemented on a thread-by-thread basis. The primary purpose of impersonation is to trigger access checks against a client's identity.

What is the use of impersonate?

impersonate, play, and act mean to pretend to be somebody else. impersonate is used when someone tries to look and sound like another person as much as possible. You're good at impersonating celebrities. play is used when someone takes a part in a play, movie, or TV show.


1 Answers

Impersonating a user using Forms Authentication can be done. The following code does work.

The Visual Studio Magazine article referred to by Robert is an excellent resource. There are a some issues with the example code in the article, so I've included some working code below.

Note: If you are using Visual Studio, make sure to launch it "Run as Administrator" to avoid problems with UAC blocking impersonation.

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

Update:

You should also handle Application_EndRequest, because calls like Response.End() will bypass Application_PostRequestHandlerExecute.

Another issue is that the WindowsIdentity may get garbage collected, so you should create a new WindowsIdentity and WindowsPrincipal from the logon token on every request.

Update2:

I'm not sure why this is getting downvoted, because it works. I've added the pinvoke signature and some test code. Again, launch Visual Studio using "Run as Administrator". Google how to do that if you don't know how.

like image 196
user281806 Avatar answered Oct 23 '22 19:10

user281806