Question

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 = "admin@domain.com";
            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);
        }
    }
}
Was it helpful?

Solution

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

OTHER TIPS

Error (0x80004005): Unspecified error

I had the some problem connecting to the remote windows authenticated with the error Error (0x80004005): Unspecified error. I resolved as follows:

//Define path
//This path uses the full path of user authentication
String path = string.Format("WinNT://{0}/{1},user", server_address, username);
DirectoryEntry deBase = null;
try
{
    //Try to connect with secure connection
    deBase = new DirectoryEntry(path, username, _passwd, AuthenticationTypes.Secure);

    //Connection test
    //After test define the deBase with the parent of user (root container)
    object nativeObject = deBase.NativeObject;
    deBase = deBase.Parent;

}
catch (Exception ex)
{
    //If an error occurred try without Secure Connection
    try
    {
        deBase = new DirectoryEntry(path, username, _passwd);

        //Connection test
        //After test define the deBase with the parent of user (root container)
        object nativeObject = deBase.NativeObject;
        deBase = deBase.Parent;
        nativeObject = deBase.NativeObject;

    }
    catch (Exception ex2)
    {
        //If an error occurred throw the error
        throw ex2;
    }
}

Hope that helps. Helvio Junior www.helviojunior.com.br

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top