0

I am writing an application allowing users to manage groups in Active Directory. I want to use the identity of the currently logged in user so that they do not have to log into the application. The application works without issue remotely but after deploying to the test server (Windows 2008R2 IIS6) it is attempting to use the IIS APPPOOL identity instead of mine.

Relevant web.config settings:

<authentication mode="Windows"></authentication>
<identity impersonate="true" />

Code to check identity:

Session("Username") = ActiveDirectory.GetUsername( _
    WindowsIdentity.GetCurrent.User.Translate(GetType(NTAccount)).Value _
)

ActiveDirectory is a class of helper functions and doesn't contain any impersonation logic.

How can I get the identity of the user accessing the application and not the IIS APPPOOL user?

Phillip Copley
  • 4,238
  • 4
  • 21
  • 38
  • What type of users are managing the groups..? is this any user..? if so `BAD IDEA` Why don't you have an AD Admin group manage that..? and another thing you could still get the Current User of the machine and keep it in a Different Session before it resolves to the Service Account or account user that you are trying to Impersonate.. – MethodMan Mar 29 '13 at 15:04
  • Only the group manager will be able to edit membership. How would I access the current machine's user before it resolves to the service account? – Phillip Copley Mar 29 '13 at 15:08
  • `var currUser= System.Security.Principal.WindowsIdentity.GetCurrent().Name.Split('\\');` – MethodMan Mar 29 '13 at 15:13
  • then you could use this bit of code to determine if the user is even in AD, `PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "MachineIP:389", "dc=dom,dc=fr", "jpb", "root.123");` for example or use the `PrincipalContext` Class – MethodMan Mar 29 '13 at 15:15
  • make sure Anonymous Authentication is turned off – Tom Stickel Jul 07 '16 at 23:55

2 Answers2

2

I believe the application will run with the identity of the application pool. In order to run as a different identity you will need to impersonate a user. MSDN has an article about it. Here is a class I wrote based off the article that helped me accomplish something similar.

class Impersonator : IDisposable
  {
      [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
      private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
          int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

      [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
      private extern static bool CloseHandle(IntPtr handle);

      WindowsIdentity newId;
      WindowsImpersonationContext impersonatedUser;
      private bool isDisposed;

      public Impersonator(string user, string password, string domain)
      {
          SafeTokenHandle safeTokenHandle;
          const int LOGON32_PROVIDER_DEFAULT = 0;
          //This parameter causes LogonUser to create a primary token. 
          const int LOGON32_LOGON_INTERACTIVE = 2;

          // Call LogonUser to obtain a handle to an access token. 
          bool returnValue = LogonUser(user, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, out safeTokenHandle);

          newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
          impersonatedUser = newId.Impersonate();
      }

      public void Dispose()
      {

          this.Dispose(true);
          GC.SuppressFinalize(this);
      }

      public void Dispose(bool disposing)
      {
          if (!this.isDisposed)
          {
              if (disposing)
              {
                  if (impersonatedUser != null)
                  {
                      this.impersonatedUser.Dispose();
                  }

                  if (newId != null)
                  {
                      this.newId.Dispose();
                  }
              }
          }

          this.isDisposed = true;
      }

      ~Impersonator()
      {
          Dispose(false);
      }

      private sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
      {
          private SafeTokenHandle()
              : base(true)
          {
          }

          [DllImport("kernel32.dll")]
          [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
          [SuppressUnmanagedCodeSecurity]
          [return: MarshalAs(UnmanagedType.Bool)]
          private static extern bool CloseHandle(IntPtr handle);

          protected override bool ReleaseHandle()
          {
              return CloseHandle(handle);
          }
      }
  }

Basically create a new instance of the class when you want to impersonate the user and dispose of the class when you are done.

I hope this helps!

MisterXero
  • 1,098
  • 2
  • 9
  • 17
  • Thanks for the comment MisterXero. This looks like you're requiring the username and password, correct? I'm looking to impersonate the user that is logged into whatever computer is accessing this site without having them log in again. – Phillip Copley Mar 29 '13 at 15:21
  • In the my application I have a separate account that has access to the active directory that I use to change the identity with (Only I know the username and password). I would find the current user by System.Web.HttpContext.Current.User.Identity. Once I have changed the identity of the application and know the user I can lookup the user in AD to see if they have permissions to change the AD. If they do then it is ok to proceed with whatever it is you need to do with AD. – MisterXero Mar 29 '13 at 15:25
1

I'm not sure if this is along the lines of what you are trying to do. But to retrieve a user you would use something like this:

WindowsIdentity user = WindowsIdentity.GetCurrent();
WindowsPrincipal role = new WindowsPrincipal(user);

With the above solution you can actually check the role as well, or define Identity.Name to supply you the information.

Another solution:

Environment.UserName;
Environment.GetEnvironmentVariable("USERNAME");

Now I know the WindowsIdentity will pull across a Domain but the others I'm not sure how they will handle Active Directory. So you might have to do something with a Domain Context.

// Define Context
PrincipalContext context = new PrincipalContext(ContextType.Domain);

// Find User
UserPrincipal user = UserPrincipal.Current;

// Check User
if (user != null)
{
    string loginName = user.SamAccountName; // Whatever "Login Name Means"
}

Here are good resources as well:

Managing Directory Security:

MSDN Docs On Account Management

Not sure if that is exactly what you meant, but hope that helps.

Greg
  • 11,302
  • 2
  • 48
  • 79
  • Thanks for answering Greg; unfortunately, the Environment variables are returning results related to the app pool or server, not my account. Basically I'm just looking to see *who* is accessing the page without having them log into the site again, by checking to see who is logged into the computer they are using. – Phillip Copley Mar 29 '13 at 15:20
  • 1
    @PhillipCopley Yeah, that is what I thought. Defining a Context may be a nice alternative then that may hit what you need. Sorry I couldn't be more of a help. I'll see if I can figure something out for you. – Greg Mar 29 '13 at 15:30