从非域计算机连接到域SQL Server 2005

几天前我问了一个问题( 从使用Windows身份validation的非域计算机访问SQL Server 2005 ),这个问题得到了一些有趣但不可用的建议。 我想再次提出这个问题,但要弄清楚我的约束是什么:

我有一个Windows域,其中一台机器运行SQL Server 2005,并配置为仅支持Windows身份validation。 我想在同一网络上的计算机上运行C#客户端应用程序,但不在域上,并访问SQL Server 2005实例上的数据库。

我不能在任何一台机器上创建或修改操作系统或SQL Server用户,我也不能对权限或模拟进行任何更改,也不能使用runas。

我知道我可以使用以下四个参数编写可以连接到SQL Server数据库的Perl和Java应用程序:服务器名称,数据库名称,用户名(域名为domain \ user)和密码。

在C#中,我尝试了各种各样的事情:

string connectionString = "Data Source=server;Initial Catalog=database;User Id=domain\user;Password=password"; SqlConnection connection = new SqlConnection(connectionString); connection.Open(); 

并尝试将集成安全性设置为真假,但似乎没有任何效果。 我想在C#中做什么根本不可能?

感谢任何帮助,马丁

正如您所说,Linux机器上的JDBC或Perl都可以使用Windows身份validation和凭据连接到SQL Server, 这些身份validation和凭据与当前登录的用户不同。 顺便说一句,Windows CE设备也是如此 。

我认为这不是C#的问题,而是SQL Server OLE DB驱动程序的问题。 我想上面提到的方法“假装是网络级别使用某些特定凭据的Windows机器”; SQL Server OLE DB驱动程序缺少的function。 因此,我的建议是寻找可以访问SQL Server数据库的替代(可能是商业?)OLE DB驱动程序。 不过,我不确定是否存在这样的事情。

我遇到了类似的问题,我正在编写一个工具,需要在一个域上的计算机上运行,​​并使用可信连接与另一个域上的SQL服务器进行身份validation。 我在这个问题上找到的一切都说不能做到。 相反,您必须加入域,使用SQL身份validation,参与一些名为Kerberos的讨论,或者让您的网络人员建立一个可信赖的关系,仅举几个选择。

事情是我知道我可以使用RUNAS以某种方式使用它因为我用SSMScertificate了它:

 C:\WINDOWS\system32\runas.exe /netonly /savecred /user:megacorp\joe.bloggs "C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\SqlWb.exe" 

/ netonly标志允许我用本地凭据执行exe并使用远程凭据访问网络,我想,无论如何我得到了我期望从远程服务器得到的结果集。 问题是runas命令使调试应用程序变得非常困难,并且它闻起来不太好。

最后我在代码项目上发现了这篇文章,该文章讨论了操作Active Directory的身份validation,以下是进行模拟的主要类:

    使用系统;
    使用System.Runtime.InteropServices;  // DllImport
    使用System.Security.Principal;  // WindowsImpersonationContext

    命名空间TestApp
     {
         class Impersonator
         {
             //组类型枚举
            枚举SECURITY_IMPERSONATION_LEVEL:int
             {
                 SecurityAnonymous = 0,
                 SecurityIdentification = 1,
                 SecurityImpersonation = 2,
                 SecurityDelegation = 3
             }

             //获取用户令牌
             [DllImport(“advapi32.dll”,SetLastError = true)]
             static extern bool LogonUser(string pszUsername,string pszDomain,string pszPassword,
                 int dwLogonType,int dwLogonProvider,ref IntPtr phToken);

             //关闭LogonUser返回的打开的handes
             [DllImport(“kernel32.dll”,CharSet = CharSet.Auto)]
             extern static bool CloseHandle(IntPtr句柄);

             //创建重复的标记句柄
             [DllImport(“advapi32.dll”,CharSet = CharSet.Auto,SetLastError = true)]
             extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
                 int SECURITY_IMPERSONATION_LEVEL,ref IntPtr DuplicateTokenHandle);

             WindowsImpersonationContext newUser;

             /// 
             ///尝试冒充用户。 如果成功,返回 
             ///新用户身份的WindowsImpersonationContext。
             /// 
             ///您要模拟的用户名
             ///登录域
             ///用户登录密码
             /// 
             public Impersonator(字符串sUsername,字符串sDomain,字符串sPassword)
             {
                 //初始化标记
                 IntPtr pExistingTokenHandle = new IntPtr(0);
                 IntPtr pDuplicateTokenHandle = new IntPtr(0);
                 pExistingTokenHandle = IntPtr.Zero;
                 pDuplicateTokenHandle = IntPtr.Zero;

                 //如果域名为空,则假设本地计算机
                 if(sDomain ==“”)
                     sDomain = System.Environment.MachineName;

                尝试
                 {
                     const int LOGON32_PROVIDER_DEFAULT = 0;

                     //创建令牌
                     // const int LOGON32_LOGON_INTERACTIVE = 2;
                     const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
                     // const int SecurityImpersonation = 2;

                     //得到令牌的句柄
                     bool bImpersonated = LogonUser(sUsername,sDomain,sPassword,
                         LOGON32_LOGON_NEW_CREDENTIALS,LOGON32_PROVIDER_DEFAULT,ref pExistingTokenHandle);

                     //模仿失败了?
                     if(false == bImpersonated)
                     {
                         int nErrorCode = Marshal.GetLastWin32Error();

                         //显示LogonUser失败的原因
                        抛出新的ApplicationException(“LogonUser()失败,错误代码为:”+ nErrorCode);
                     }

                     bool bRetVal = DuplicateToken(pExistingTokenHandle,(int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,ref pDuplicateTokenHandle);

                     // DuplicateToken失败了吗?
                     if(false == bRetVal)
                     {
                         int nErrorCode = Marshal.GetLastWin32Error();
                         CloseHandle的(pExistingTokenHandle);  //关闭现有句柄

                         //显示DuplicateToken失败的原因
                        抛出新的ApplicationException(“DuplicateToken()失败,错误代码为:”+ nErrorCode);
                     }
                    其他
                     {
                         //使用新的主令牌创建新身份
                         WindowsIdentity newId =新的WindowsIdentity(pDuplicateTokenHandle);
                         WindowsImpersonationContext impersonatedUser = newId.Impersonate();

                         newUser = impersonatedUser;
                     }
                 }
                最后
                 {
                     //关闭句柄
                     if(pExistingTokenHandle!= IntPtr.Zero)
                         CloseHandle的(pExistingTokenHandle);
                     if(pDuplicateTokenHandle!= IntPtr.Zero)
                         CloseHandle的(pDuplicateTokenHandle);
                 }
             }

             public void Undo()
             {
                 newUser.Undo();
             }
         }
     }

要使用它:

 Impersonator impersonator = new Impersonator("username", "domain", "password"); //Connect to and use SQL server impersonator.Undo(); 

我添加了Undo方法,否则模仿对象往往会收集垃圾。 我还修改了代码以使用LOGON32_LOGON_NEW_CREDENTIALS但这是一个戳并运行以使其工作; 我仍然需要完全理解它的作用,我感觉它与runas上的/ netonly标志相同。 我也打算稍微分解一下构造函数。

在连接字符串中指定用户名和密码是没用的,因为这些意味着SQL身份validation,并且您已经指定SQL Server只接受Windows身份validation。

如果服务器不允许SQL身份validation,那么连接的唯一可能性是使用Windows身份validation,即。 IntegratedSecurity=true 。 这意味着您的客户端将进行身份validation,因为任何凭据正在运行该流程(或当前正在模拟)。

要使Windows身份validation起作用,您必须选择以下选项之一:

  • 将非域加入的计算机加入到信任服务器域的域(可以是它自己的域!)中,然后将客户端进程作为域\用户凭据运行。
  • 使用NTLM镜像帐户:客户端上的一对本地用户和具有相同名称和密码的服务器。
  • 授予ANONYMOUS访问SQL Server的权限。

如果您无法使客户端主机信任服务器域,也无法添加NTLM镜像帐户,并且SQL Server管理员足够理智,不启用ANONYMOUS,那么您将无法连接。

您必须配置SQL Server以允许SQL Server身份validation,即使用用户名和密码进行身份validation。

您无法通过域用户名/密码进行身份validation,例如’服务器身份validation,即直接指定域用户名/密码。

我当然可能是错的,但我确信这不是C#或.NET的问题。 如何在Perl或Java应用程序中登录SQL Server?

我会给你一些我更熟悉的Java答案:我使用jTDS JDBC驱动程序和上面提到的四个参数。 Perl应用程序我不太了解,但是在Linux机器上运行,并且能够连接相同的参数。 我无法更改SQL Server以支持SQL身份validation。

为了回答Remus的建议,我不能做他建议的那三件事,但Java和Perl应用程序能够连接。 还有其他想法吗?

谢谢,马丁

提示输入凭据是一种选择吗?

以下是我使用jTDS JDBC驱动程序从非域计算机连接的示例代码:

的Class.forName( “net.sourceforge.jtds.jdbc.Driver”)的newInstance(); String url =“jdbc:jtds:sqlserver:// server / database; domain = domain”; conn = DriverManager.getConnection(url,“user”,“password”);