Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impersonation and DirectoryEntry

I am impersonating a user account successfully, but I am not able to use the impersonated account to bind to AD and pull down a DirectoryEntry.

The below code outputs:

  • Before impersonation I am: DOMAIN\user
  • After impersonation I am: DOMAIN\admin
  • Error: C:\Users\user\ADSI_Impersonation\bin\Debug\ADSI_Impersonation.exe samaccountname:

My issue seems similar to:

How to use the System.DirectoryServices namespace in ASP.NET

I am obtaining a primary token. I understand that I need to use delegation to use the impersonated token on a remote computer. I confirmed that the account doesn't have the flag checked "Account is sensitive and cannot be delegated". I also confirmed that the Local Group Policy and Domain Group Policies are not preventing delegation:

Computer Configuration\Windows Settings\Security Settings\Local Policies\User Rights Assignment\

What am I missing?

Thanks!

using System;
using System.DirectoryServices;
using System.Security;
using System.Security.Principal;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.Runtime.ConstrainedExecution;

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

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

        static void Main(string[] args)
        {
            const int LOGON32_PROVIDER_DEFAULT = 0;
            const int LOGON32_LOGON_INTERACTIVE = 2;

            string userName = "[email protected]";
            string password = "password";

            Console.WriteLine("Before impersonation I am: " + WindowsIdentity.GetCurrent().Name);

            SafeTokenHandle safeTokenHandle;

            try
            {
                bool returnValue = LogonUser(userName, null, password,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    out safeTokenHandle);

                if (returnValue)
                {
                    WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
                    WindowsImpersonationContext impersonatedUser = newId.Impersonate();
                }
                else
                {
                    Console.WriteLine("Unable to create impersonatedUser.");
                    return;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Authentication error.\r\n" + e.Message);
            }

            Console.WriteLine("After impersonation I am: " + WindowsIdentity.GetCurrent().Name);

            string OU = "LDAP://dc=domain,dc=com";
            DirectoryEntry entry = new DirectoryEntry(OU);
            entry.AuthenticationType = AuthenticationTypes.Secure;

            DirectorySearcher mySearcher = new DirectorySearcher();
            mySearcher.SearchRoot = entry;
            mySearcher.SearchScope = System.DirectoryServices.SearchScope.Subtree;
            mySearcher.PropertiesToLoad.Add("cn");
            mySearcher.PropertiesToLoad.Add("samaccountname");

            string cn = "fistname mi. lastname";
            string samaccountname = "";

            try
            {
                // Create the LDAP query and send the request
                mySearcher.Filter = "(cn=" + cn + ")";

                SearchResultCollection searchresultcollection = mySearcher.FindAll();

                DirectoryEntry ADentry = searchresultcollection[0].GetDirectoryEntry();

                Console.WriteLine("samaccountname: " + ADentry.Properties["samaccountname"].Value.ToString());
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }

            Console.WriteLine("samaccountname: " + samaccountname);
            Console.ReadLine();
        }
    }

    public 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);
        }
    }
}
like image 519
Elijah W. Gagne Avatar asked Jan 22 '12 00:01

Elijah W. Gagne


People also ask

What is impersonation in authentication?

Impersonation is the process of assigning a user account to an unknown user.

What is impersonation in MVC?

Impersonation allows machine to machine impersonation, so the client browser and the server are on the same page when it comes to the impersonation.

What is Active Directory impersonation?

Impersonation is the ability of a thread to execute in a security context different from that of the process owning the thread. The server thread uses an access token representing the client's credentials, and with this, it can access resources that the client can access.

How does impersonation work?

Impersonation enables a caller to impersonate a given user account. This enables the caller to perform operations by using the permissions that are associated with the impersonated account, instead of the permissions that are associated with the caller's account.


1 Answers

Many .NET APIs do not take your manual impersonation into consideration, such as the LDAP queries you noticed. Therefore, you need to use the overloading constructors of DirectoryEntry instead,

http://msdn.microsoft.com/en-us/library/bw8k1as4.aspx

http://msdn.microsoft.com/en-us/library/wh2h7eed.aspx

like image 199
Lex Li Avatar answered Oct 05 '22 06:10

Lex Li