【问题标题】:.net impersonate not passing proper credentials to SQL Server.net 模拟未将正确的凭据传递给 SQL Server
【发布时间】:2018-10-28 05:19:19
【问题描述】:

我目前有一个 .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">
....
....

【问题讨论】:

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


    【解决方案1】:

    如果进程在域帐户下运行时它可以工作,但在模拟域帐户时不起作用,我很确定这是因为模拟不会在机器之间流动。来自MSDN

    模拟将原始调用者的身份流向同一台计算机上的后端资源。委派将原始调用者的身份流向后端资源,而不是运行服务的计算机。

    您的 SQL Server 可能在另一台机器上,因此尽管您是在模拟,但当进程开始与另一台机器通信时,它会开始使用启动该进程的原始帐户。

    因此,您需要使用委托

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

    【讨论】:

    • 阅读 MSDN 文章后,我不确定是否需要委托以及它是否适用于我的上下文。有没有办法在连接字符串中使用域帐户和密码并将其视为 Windows 身份验证?实现这一目标的唯一方法是使用模拟吗?在域帐户下运行进程时它确实有效,但在安全模型中这是不可能的,我必须在不允许这样做的地方工作(在任务调度程序中存储凭据)
    【解决方案2】:

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

    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));
    

    然后使用域中提供的帐户信息、用户名和密码在上下文中执行方法processReport(string[] args)。如果需要,这些也可以是安全字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-10
      • 1970-01-01
      • 2012-01-28
      相关资源
      最近更新 更多