简体   繁体   English

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

[英]Connect to domain SQL Server 2005 from non-domain machine

I asked a question a few days ago ( Access to SQL Server 2005 from a non-domain machine using Windows authentication ) which got some interesting, but not usable suggestions. 几天前我问了一个问题( 使用Windows身份验证从非域计算机访问SQL Server 2005 ),这提出了一些有趣但不可用的建议。 I'd like to ask the question again, but make clear what my constraints are: 我想再次提出这个问题,但要弄清楚我的约束是什么:

I have a Windows domain within which a machine is running SQL Server 2005 and which is configured to support only Windows authentication. 我有一个Windows域,其中一台机器运行SQL Server 2005,并配置为仅支持Windows身份验证。 I would like to run a C# client application on a machine on the same network, but which is NOT on the domain, and access a database on the SQL Server 2005 instance. 我想在同一网络上的计算机上运行C#客户端应用程序,但不在域上,并访问SQL Server 2005实例上的数据库。

I CANNOT create or modify OS or SQL Server users on either machine, and I CANNOT make any changes to permissions or impersonation, and I CANNOT make use of runas. 我不能在任何一台机器上创建或修改操作系统或SQL Server用户,我也不能对权限或模拟进行任何更改,我也不能使用runas。

I know that I can write Perl and Java applications that can connect to the SQL Server database using only these four parameters: server name, database name, username (in the form domain\\user), and password. 我知道我可以使用以下四个参数编写可以连接到SQL Server数据库的Perl和Java应用程序:服务器名称,数据库名称,用户名(域名为domain \\ user)和密码。

In C# I have tried various things around: 在C#中,我尝试过各种各样的事情:

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

and tried setting integrated security to true and false, but nothing seems to work. 并尝试将集成安全性设置为真假,但似乎没有任何效果。 Is what I am trying to do simply impossible in C#? 我想在C#中做什么根本不可能?

Thanks for any help, Martin 感谢任何帮助,马丁

I had a similar problem where I was writing a tool that needed to run on a machine on one domain and authenticate with a SQL server on another domain using a trusted connection. 我遇到了类似的问题,我正在编写一个工具,需要在一个域上的计算机上运行,​​并使用可信连接与另一个域上的SQL服务器进行身份验证。 Everything I could find on the subject said it couldn't be done. 我在这个问题上找到的一切都说不能做到。 Instead you must join the domain, use SQL authentication, get involved with some chap called Kerberos, or get your network guys to setup a trusted relationship, to name a few alternatives. 相反,你必须加入域,使用SQL身份验证,参与一些名为Kerberos的讨论,或者让你的网络人员建立一个可信赖的关系,举几个选择。

The thing is I knew I could get it working in some way using RUNAS because I'd proven it with SSMS: 事情是我知道我可以使用RUNAS以某种方式使用它,因为我用SSMS证明了它:

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"

The /netonly flag allowed me to execute the exe with the local credentials and access the network with the remote credentials, I think, anyway I got the result set I expected from the remote server. / netonly标志允许我用本地凭据执行exe并使用远程凭据访问网络,我想,无论如何我得到了我期望从远程服务器得到的结果集。 The problem was the runas command made it very difficult to debug the application, and it didn't smell good. 问题是runas命令使调试应用程序变得非常困难,并且它闻起来并不好。

Eventually I found this article on the code project which was talking about authenticating to manipulate Active Directory, Here is the main class that does the impersonation: 最后我发现这篇关于代码项目的文章正在讨论操作Active Directory的身份验证,这是进行模拟的主要类:

using System;
    using System.Runtime.InteropServices;  // DllImport
    using System.Security.Principal; // WindowsImpersonationContext

    namespace TestApp
    {
        class Impersonator
        {
            // group type enum
            enum SECURITY_IMPERSONATION_LEVEL : int
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3
            }

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

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

            // creates duplicate token handle
            [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
            extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
                int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);

            WindowsImpersonationContext newUser;

            /// 
            /// Attempts to impersonate a user.  If successful, returns 
            /// a WindowsImpersonationContext of the new users identity.
            /// 
            /// Username you want to impersonate
            /// Logon domain
            /// User's password to logon with
            /// 
            public Impersonator(string sUsername, string sDomain, string sPassword)
            {
                // initialize tokens
                IntPtr pExistingTokenHandle = new IntPtr(0);
                IntPtr pDuplicateTokenHandle = new IntPtr(0);
                pExistingTokenHandle = IntPtr.Zero;
                pDuplicateTokenHandle = IntPtr.Zero;

                // if domain name was blank, assume local machine
                if (sDomain == "")
                    sDomain = System.Environment.MachineName;

                try
                {
                    const int LOGON32_PROVIDER_DEFAULT = 0;

                    // create token
                    // const int LOGON32_LOGON_INTERACTIVE = 2;
                    const int LOGON32_LOGON_NEW_CREDENTIALS = 9;
                    //const int SecurityImpersonation = 2;

                    // get handle to token
                    bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
                        LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, ref pExistingTokenHandle);

                    // did impersonation fail?
                    if (false == bImpersonated)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();

                        // show the reason why LogonUser failed
                        throw new ApplicationException("LogonUser() failed with error code: " + nErrorCode);
                    }

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

                    // did DuplicateToken fail?
                    if (false == bRetVal)
                    {
                        int nErrorCode = Marshal.GetLastWin32Error();
                        CloseHandle(pExistingTokenHandle); // close existing handle

                        // show the reason why DuplicateToken failed
                        throw new ApplicationException("DuplicateToken() failed with error code: " + nErrorCode);
                    }
                    else
                    {
                        // create new identity using new primary token
                        WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
                        WindowsImpersonationContext impersonatedUser = newId.Impersonate();

                        newUser = impersonatedUser;
                    }
                }
                finally
                {
                    // close handle(s)
                    if (pExistingTokenHandle != IntPtr.Zero)
                        CloseHandle(pExistingTokenHandle);
                    if (pDuplicateTokenHandle != IntPtr.Zero)
                        CloseHandle(pDuplicateTokenHandle);
                }
            }

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

To use it just: 要使用它:

Impersonator impersonator = new Impersonator("username", "domain", "password");

//Connect to and use SQL server

impersonator.Undo();

I added in the Undo method otherwise the impersonator object tended to get garbage collected. 我添加了Undo方法,否则模仿对象往往会收集垃圾。 I also altered the code to use LOGON32_LOGON_NEW_CREDENTIALS but this was a poke and run to make it work; 我还修改了代码以使用LOGON32_LOGON_NEW_CREDENTIALS,但这是一个戳并运行以使其工作; I still need to understand fully what it does, I have a feeling its the same as the /netonly flag on runas. 我仍然需要完全理解它的作用,我感觉它和runas上的/ netonly标志一样。 I'm also going to break down the constructor a bit. 我也打算稍微分解一下构造函数。

Is useless to specify user name and password in connection string because those imply SQL Authentication, and you already specified that SQL Server only accepts Windows authentication. 在连接字符串中指定用户名和密码是没用的,因为这些意味着SQL身份验证,并且您已经指定SQL Server仅接受Windows身份验证。

If the server doesn't allow SQL Authentication then the only possibility to connect is to use Windows authentication, ie. 如果服务器不允许SQL身份验证,那么连接的唯一可能性是使用Windows身份验证,即。 IntegratedSecurity=true . IntegratedSecurity=true Which means that your client will authenticate as whatever credential is running the process (or is being currently impersonated). 这意味着您的客户端将进行身份验证,因为任何凭据正在运行该进程(或当前正在模拟)。

In order for Windows authentication to work, you have to choose one of the following: 要使Windows身份验证起作用,您必须选择以下选项之一:

  • Join the non-domain joined machine into a domain (it can be it's own domain!) that trusts the server domain, then run the client process as a domain\\user credential. 将非域加入的计算机加入到信任服务器域的域(可以是它自己的域!)中,然后将客户端进程作为域\\用户凭据运行。
  • Use NTLM mirrored accounts: a pair of local users on the client and the server with identical name and passwords. 使用NTLM镜像帐户:客户端上的一对本地用户和具有相同名称和密码的服务器。
  • Grant as ANONYMOUS access to the SQL Server. 授予ANONYMOUS访问SQL Server的权限。

If you cannot make the client host trust the server domain, nor can you add NTLM mirrored accounts, and the SQL Server admin is sane enough not to enable ANONYMOUS then you won't be able to connect. 如果您无法使客户端主机信任服务器域,也无法添加NTLM镜像帐户,并且SQL Server管理员足够理智,不启用ANONYMOUS,那么您将无法连接。

You have to configure SQL Server to allow SQL Server Authentication, ie authentication using username and password. 您必须配置SQL Server以允许SQL Server身份验证,即使用用户名和密码进行身份验证。

You can't authenticate by domain username/password 'like' server authentication, ie specify domain username/password directly. 您无法通过域用户名/密码进行身份验证,例如'服务器身份验证,即直接指定域用户名/密码。

I can be wrong of course, but I'm sure that this isn't a problem of C# or .NET. 我当然可能是错的,但我确信这不是C#或.NET的问题。 How can you login on SQL Server in your Perl or Java application?? 如何在Perl或Java应用程序中登录SQL Server?

As you correctly say, JDBC or Perl on a Linux machine can both connect to an SQL Server using Windows authentication and credentials which differ from the currently logged on user. 正如您所说,Linux机器上的JDBC或Perl都可以使用Windows身份验证和凭据连接到SQL Server, 这些身份验证和凭据与当前登录的用户不同。 The same is true for Windows CE devices , by the way. 顺便说一句,Windows CE设备也是如此

I think that this is that this is not an issue of C# but of the SQL Server OLE DB driver. 我认为这不是C#的问题,而是SQL Server OLE DB驱动程序的问题。 I guess the methods mentioned above "pretend to be a Windows machine using some specific credentials" on the network level; 我猜上面提到的方法“假装是网络级别使用某些特定凭据的Windows机器”; a feature, which the SQL Server OLE DB driver lacks. SQL Server OLE DB驱动程序缺少的功能。 Thus, my suggestion would be to look for an alternative (maybe commercial?) OLE DB driver that can access SQL Server databases. 因此,我的建议是寻找可以访问SQL Server数据库的替代(可能是商业?)OLE DB驱动程序。 I'm not sure if such a thing exists, though. 不过,我不确定是否存在这样的事情。

I'll give you the Java answer which I'm more familiar with: I use the jTDS JDBC driver with the four parameters mentioned above. 我会给你一个我更熟悉的Java答案:我使用jTDS JDBC驱动程序和上面提到的四个参数。 The Perl application I know less about, but is running on a Linux box, and is able to connect with the same parameters. Perl应用程序我不太了解,但是在Linux机器上运行,并且能够连接相同的参数。 I cannot change the SQL Server to support SQL Authentication. 我无法更改SQL Server以支持SQL身份验证。

To answer Remus' suggestions, I cannot do any of those three things he suggests and yet Java and Perl applications are able to connect. 为了回答Remus的建议,我不能做他建议的那三件事,但Java和Perl应用程序能够连接。 Any other ideas? 还有其他想法吗?

Thanks, Martin 谢谢,马丁

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

Here is the sample code that I use to connect from a non-domain machine using the jTDS JDBC driver: 以下是我使用jTDS JDBC驱动程序从非域计算机连接的示例代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Windows身份验证从非域计算机访问SQL Server 2005 - Access to SQL Server 2005 from a non-domain machine using Windows authentication Windows Forms 来自非域添加机器的模拟 - Windows Forms Impersonation from a non-Domain added machine 在非域计算机上使用域控制器以编程方式同步时间 - programmatically sync time on non-domain machine with domain controller C#ActiveDirectory - 如何从已加入域的计算机远程添加本地用户帐户到非域计算机 - C# ActiveDirectory - How do I add a local user account remotely from a domain-joined machine to a non-domain machine 如何列出非域计算机上运行代码的域? - How to list domains running code from a non-domain computer? 如何在非域xp计算机上与域控制器同步时间? - how to sync time on a non-domain xp computer with domain controller? 如何列出从非域计算机运行代码的所有域中的用户? - How to list users in all domains running code from a non-domain computer? 在非域帐户上使用带有服务帐户凭据的Google API - Using Google API With Service Account Credentials on a non-domain account ASP.NET Boilerplate Domain Layer似乎包含非Domain类 - ASP.NET Boilerplate Domain Layer appears to contain non-Domain classes 将C#连接到其他域中的SQL Server - Connect c# to a SQL Server in different domain
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM