Hi, I ask you for a problem I can't resolve.

I'm developing a form application in C# and I need to access a web application (IIS) within the intranet and not to insert crediantials manually (I keep them in code).

I tried using both Win32NativeMethods.LogonUser and advapi32.dll's Logon User methods, but they both return false. Why? Username, domain and password I use are profiled on the remote machine, not on my local machine. Might this be the problem?

There are some solutions on the web but they don't work for me.

Could you help me, please?

Following is the code I tried to use (references: http://platinumdogs.wordpress.com/2008/10/30/net-c-impersonation-with-network-credentials/#comment-770)

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.IO;
using System.Security.Principal;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace OpenWebBrowser_authenticated_CS
{
    class Program
    {
        [STAThread]
        static void Main(string[] args)
        {
            using (new Impersonator("username", "domain", "password"))
            {
                string siteUrl = "http://mywebapplication";                

                System.Diagnostics.Process.Start(siteUrl);
            }
        }
    }

    public enum LogonType
    {
        LOGON32_LOGON_INTERACTIVE = 2,
        LOGON32_LOGON_NETWORK = 3,
        LOGON32_LOGON_BATCH = 4,
        LOGON32_LOGON_SERVICE = 5,
        LOGON32_LOGON_UNLOCK = 7,
        LOGON32_LOGON_NETWORK_CLEARTEXT = 8, // Win2K or higher
        LOGON32_LOGON_NEW_CREDENTIALS = 9 // Win2K or higher
    };

    public enum LogonProvider
    {
        LOGON32_PROVIDER_DEFAULT = 0,
        LOGON32_PROVIDER_WINNT35 = 1,
        LOGON32_PROVIDER_WINNT40 = 2,
        LOGON32_PROVIDER_WINNT50 = 3
    };

    public enum ImpersonationLevel
    {
        SecurityAnonymous = 0,
        SecurityIdentification = 1,
        SecurityImpersonation = 2,
        SecurityDelegation = 3
    }

    class Win32NativeMethods
    {
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern int LogonUser(string lpszUserName,
             string lpszDomain,
             string lpszPassword,
             int dwLogonType,
             int dwLogonProvider,
             ref IntPtr phToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int DuplicateToken(IntPtr hToken,
              int impersonationLevel,
              ref IntPtr hNewToken);

        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool RevertToSelf();

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

    /// <summary>
    /// Allows code to be executed under the security context of a specified user account.
    /// </summary>
    /// <remarks> 
    ///
    /// Implements IDispose, so can be used via a using-directive or method calls;
    ///  ...
    ///
    ///  var imp = new Impersonator( "myUsername", "myDomainname", "myPassword" );
    ///  imp.UndoImpersonation();
    ///
    ///  ...
    ///
    ///   var imp = new Impersonator();
    ///  imp.Impersonate("myUsername", "myDomainname", "myPassword");
    ///  imp.UndoImpersonation();
    ///
    ///  ...
    ///
    ///  using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
    ///  {
    ///   ...
    ///   [code that executes under the new context]
    ///   ...
    ///  }
    ///
    ///  ...
    /// </remarks>
    public class Impersonator : IDisposable
    {
        private WindowsImpersonationContext _wic;

        /// <summary>
        /// Begins impersonation with the given credentials, Logon type and Logon provider.
        /// </summary>
        ///<param name="userName">Name of the user.</param>
        ///<param name="domainName">Name of the domain.</param>
        ///<param name="password">The password. <see cref="System.String"/></param>
        ///<param name="logonType">Type of the logon.</param>
        ///<param name="logonProvider">The logon provider. <see cref="Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider"/></param>
        public Impersonator(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
        {
            Impersonate(userName, domainName, password, logonType, logonProvider);
        }

        /// <summary>
        /// Begins impersonation with the given credentials.
        /// </summary>
        ///<param name="userName">Name of the user.</param>
        ///<param name="domainName">Name of the domain.</param>
        ///<param name="password">The password. <see cref="System.String"/></param>
        public Impersonator(string userName, string domainName, string password)
        {
            Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Impersonator"/> class.
        /// </summary>
        public Impersonator()
        { }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            UndoImpersonation();
        }

        /// <summary>
        /// Impersonates the specified user account.
        /// </summary>
        ///<param name="userName">Name of the user.</param>
        ///<param name="domainName">Name of the domain.</param>
        ///<param name="password">The password. <see cref="System.String"/></param>
        public void Impersonate(string userName, string domainName, string password)
        {
            Impersonate(userName, domainName, password, LogonType.LOGON32_LOGON_INTERACTIVE, LogonProvider.LOGON32_PROVIDER_DEFAULT);
        }

        /// <summary>
        /// Impersonates the specified user account.
        /// </summary>
        ///<param name="userName">Name of the user.</param>
        ///<param name="domainName">Name of the domain.</param>
        ///<param name="password">The password. <see cref="System.String"/></param>
        ///<param name="logonType">Type of the logon.</param>
        ///<param name="logonProvider">The logon provider. <see cref="Mit.Sharepoint.WebParts.EventLogQuery.Network.LogonProvider"/></param>
        public void Impersonate(string userName, string domainName, string password, LogonType logonType, LogonProvider logonProvider)
        {
            UndoImpersonation();

            IntPtr logonToken = IntPtr.Zero;
            IntPtr logonTokenDuplicate = IntPtr.Zero;
            try
            {
                // revert to the application pool identity, saving the identity of the current requestor
                _wic = WindowsIdentity.Impersonate(IntPtr.Zero);

                // do logon & impersonate
                if (Win32NativeMethods.LogonUser(userName,
                    domainName,
                    password,
                    (int)logonType,
                    (int)logonProvider,
                    ref logonToken) != 0)
                {
                    if (Win32NativeMethods.DuplicateToken(logonToken, (int)ImpersonationLevel.SecurityImpersonation, ref logonTokenDuplicate) != 0)
                    {
                        WindowsIdentity wi = new WindowsIdentity(logonTokenDuplicate);
                        wi.Impersonate(); // discard the returned identity context (which is the context of the application pool)
                    }
                    else
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                }
                else
                    throw new Win32Exception(Marshal.GetLastWin32Error());
            }
            finally
            {
                if (logonToken != IntPtr.Zero)
                    Win32NativeMethods.CloseHandle(logonToken);

                if (logonTokenDuplicate != IntPtr.Zero)
                    Win32NativeMethods.CloseHandle(logonTokenDuplicate);
            }
        }

        /// <summary>
        /// Stops impersonation.
        /// </summary>
        private void UndoImpersonation()
        {
            // restore saved requestor identity
            if (_wic != null)
                _wic.Undo();
            _wic = null;
        }
    }
}

I am not sure if this will help, but I wrote an Active Directory tool that needed to run on administrator credentials, here is the code. Hope this helps or at least points you in the right direction.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Principal;


namespace ActiveDirectoryTool
{
  public static class Program
    {
        
        /* The main entry point for the application. */
         

      /*We use the DllImport class to import the advapi32.dll, this allows the application to run 
       *as another user on the network*/
      [DllImport("advapi32.dll", SetLastError = true)]

      public static extern bool LogonUser(string lpszUsername,
                                          string lpszDomain,
                                          string lpszPassword,
                                          int dwLogonType,
                                          int dwLogonProvider,
                                          ref IntPtr phToken);
      
      [STAThread]
        
      
      
      static void Main()
        {

            /*Create an instance of the tokenHandle.
             *This allows the same permissions on the network as the impersonated user.*/
            IntPtr tokenHandle = new IntPtr(0);

           /*Create a variable to check the validity of the credentials.
            *returnValue will contain a value of True if the credentials are valid.
            *returnValue will contain a value of False if the credentials are invalid.*/
            bool returnValue = LogonUser("administrator", "rashawnsanchez.net", "password123$", 2, 0, ref tokenHandle);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            /* If returnValue returns false...*/
            if (returnValue == false)
            {
               /*Retrieve the reason why.*/
               int ret = Marshal.GetLastWin32Error();

               /*Throw an exception or error and notify the user.*/
               throw new System.ComponentModel.Win32Exception(ret);
            }
            else /*Or Else.*/
            {
                /*Create the 'ID' object and pass the tokenHandle to the new ID object.*/
                WindowsIdentity ID = new WindowsIdentity(tokenHandle);

                /*Close the handle.*/
                CloseHandle(tokenHandle);

                /*Now impersonate the ID.*/
                ID.Impersonate();

                /*Now start the application.*/
                Application.Run(new Form1()); 
    
            }
    
        }
    }
}

Thanks for your answer.

Does this tool run on your local machine and access to a different machine using an account that may not be valid on local machine?

I’m on a machine A and I want to access web-application on machine B using a domain account that has permissions on machine B, but I don’t want to type username and password manually.

I am not sure if this will help, but I wrote an Active Directory tool that needed to run on administrator credentials, here is the code. Hope this helps or at least points you in the right direction.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Security.Principal;


namespace ActiveDirectoryTool
{
  public static class Program
    {
        
        /* The main entry point for the application. */
         

      /*We use the DllImport class to import the advapi32.dll, this allows the application to run 
       *as another user on the network*/
      [DllImport("advapi32.dll", SetLastError = true)]

      public static extern bool LogonUser(string lpszUsername,
                                          string lpszDomain,
                                          string lpszPassword,
                                          int dwLogonType,
                                          int dwLogonProvider,
                                          ref IntPtr phToken);
      
      [STAThread]
        
      
      
      static void Main()
        {

            /*Create an instance of the tokenHandle.
             *This allows the same permissions on the network as the impersonated user.*/
            IntPtr tokenHandle = new IntPtr(0);

           /*Create a variable to check the validity of the credentials.
            *returnValue will contain a value of True if the credentials are valid.
            *returnValue will contain a value of False if the credentials are invalid.*/
            bool returnValue = LogonUser("administrator", "rashawnsanchez.net", "password123$", 2, 0, ref tokenHandle);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            /* If returnValue returns false...*/
            if (returnValue == false)
            {
               /*Retrieve the reason why.*/
               int ret = Marshal.GetLastWin32Error();

               /*Throw an exception or error and notify the user.*/
               throw new System.ComponentModel.Win32Exception(ret);
            }
            else /*Or Else.*/
            {
                /*Create the 'ID' object and pass the tokenHandle to the new ID object.*/
                WindowsIdentity ID = new WindowsIdentity(tokenHandle);

                /*Close the handle.*/
                CloseHandle(tokenHandle);

                /*Now impersonate the ID.*/
                ID.Impersonate();

                /*Now start the application.*/
                Application.Run(new Form1()); 
    
            }
    
        }
    }
}

The code above allows your application to perform tasks at the same permission level as the impersonated user. This allows administrative tasks to be accomplished by non-administrators. This is the same concept as doing a "Run As". Hope this helps, I am sure that there a process similar to this for web applications. In addition, I wired the credentials into the program.cs itself. You will have to manually update the credentials should the impersonated users password change, etc.

The problem is that I cannot use the "Run As" with a user not profiled on the local machine.
I just want to avoid to type username and password for a web application.

Should I assume that there is no solution for this problem?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.