.net冒充不将正确的凭据传递给SQL Server

时间:2018-05-17 20:19:32

标签: c# .net sql-server connection-string impersonation

我目前有一个.net控制台应用程序需要通过appConfig文件接收活动域帐户才能连接到数据库。该应用程序正在从TaskScheduler执行。我无法使用域帐户执行任务,因为这是一个安全设置(保存密码)。

我在合并设置文件(appSettings.config)中有连接字符串,并在控制台应用设置文件中设置了身份,包括用户名和密码

我的问题是如何使用任务调度程序执行作业并在配置文件中包含用户名/密码?

在测试中,我使用了"本地服务"帐号和"网络服务"帐户并从SQL Server"

收到登录错误
  

用户' DOMAIN_NAME \ MACHINE_NAME $'登录失败。原因:不能   找到与提供的名称相匹配的登录名。 [客户:xxx.xxx.xx.xx(ip   客户机的地址)]

如果我使用具有管理员权限的本地帐户,则会返回以下错误:

  

登录失败。登录来自不受信任的域,无法使用   使用Windows身份验证。 [客户:xxx.xxx.xx.xx]

备注:

所有计算机都在同一个域上并具有连接性

当任务设置为以域帐户运行,并且身份标签没有用户名/密码时,任务按设计执行。

appSettings.config

    <?xml version="1.0"?>
    <appSettings>    
        <!-- CONNECTION STRINGS -->
        <add key="connectionString"                 value="Data Source=DB_SERVER_NAME;Initial Catalog=DB_NAME;Integrated Security=SSPI;" />
.....
.....

application.exe.config

   <?xml version="1.0"?>
    <configuration>
      <configSections>

      </configSections>  
     <appSettings file="F:\SPASystems\Conf\appSettings.config" />
      <system.web>  
      <identity impersonate="true" userName="DOMAIN_NAME\svc.ACCOUNT_NAME.user" password="dummy_password"/>
        <membership defaultProvider="ClientAuthenticationMembershipProvider">
....
....

2 个答案:

答案 0 :(得分:1)

如果进程在域帐户下运行但在模拟域帐户时不起作用,我很确定这是因为模拟不会从一台机器流到另一台机器。来自MSDN

  

模拟将原始呼叫者的身份传递到同一台计算机上的后端资源。委托将原始呼叫者的身份传递给运行该服务的计算机以外的计算机上的后端资源。

您的SQL Server可能位于不同的计算机上,因此尽管您正在模拟,但当该进程开始与另一台计算机通信时,它将开始使用该进程启动时的原始帐户。

因此,您需要使用委派

您可能还会发现this thread有帮助。

答案 1 :(得分:0)

我的最终解决方案是使用模拟,并将委托方法传递给该方法,以在模拟上下文中执行。 这些是我用来完成此任务的代码片段:

elm-lang/websocket

然后我可以通过以下方式调用和使用模拟上下文:

internal class NativeMethods
    {
        // closes open handes returned by LogonUser
        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        // obtains user token
        [DllImport("advapi32.dll", SetLastError = true)]
        public static extern bool LogonUser(string pszUsername, string pszDomain, string pszPassword,
            int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
    }

[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
    public sealed class Impersonation
    {
        /// <summary>
        /// impersonates a user based on username/password provided. executed method after impersonation and then reverts impersonation when task/method is complete.
        /// </summary>
        /// <param name="userName">username to impersonate</param>
        /// <param name="password">password for user account</param>
        /// <param name="domain">domain of user to impersonate</param>
        /// <param name="action">method to invoke after impersonation</param>
        /// <param name="logonType">LogonType to use, defaulted to Network</param>
        /// <param name="logonProvider">LogonProvider type, defaulted to default</param>
        public static void impersonate(string userName, string password, string domain, Action action, int logonType = 2, int logonProvider = 0)
        {
            //elevate privileges before doing file copy to handle domain security
            WindowsImpersonationContext context = null;
            IntPtr userHandle = IntPtr.Zero;
            try
            {
                Console.WriteLine("windows identify before impersonation: " + WindowsIdentity.GetCurrent().Name);
                // Call LogonUser to get a token for the user
                bool loggedOn = NativeMethods.LogonUser(userName,
                                            domain,
                                            password,
                                            logonType,
                                            logonProvider,
                                            ref userHandle);
                if (!loggedOn)
                {
                    Console.WriteLine("Exception impersonating user, error code: " + Marshal.GetLastWin32Error());
                }

                // Begin impersonating the user
                context = WindowsIdentity.Impersonate(userHandle);

                Console.WriteLine("windows identify after impersonation: " + WindowsIdentity.GetCurrent().Name);                
                //execute actions under impersonated user
                action();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception impersonating user: " + ex.Message);
            }
            finally
            {
                // Clean up
                if (context != null)
                {
                    context.Undo();
                }

                if (userHandle != IntPtr.Zero)
                {
                    NativeMethods.CloseHandle(userHandle);
                }
            }
        }

然后使用上下文中提供的帐户信息,用户名和密码在上下文中执行方法Impersonation.impersonate(impersonationUserName, impersonationPassword, impersonationDomain, () => processReport(args)); 。如果需要,这些也可以是安全字符串。