Подключение к домену SQL Server 2005 с компьютера, не входящего в домен - PullRequest
8 голосов
/ 13 мая 2010

Я задал вопрос несколько дней назад ( Доступ к SQL Server 2005 с компьютера, не входящего в домен, с использованием аутентификации Windows ), который получил несколько интересных, но не пригодных для использования предложений. Я хотел бы снова задать вопрос, но уточнить, каковы мои ограничения:

У меня есть домен Windows, в котором машина работает под управлением SQL Server 2005 и настроена для поддержки только аутентификации Windows. Я хотел бы запустить клиентское приложение C # на компьютере в той же сети, но не в домене, и получить доступ к базе данных на экземпляре SQL Server 2005.

Я НЕ МОГУ создавать или изменять пользователей ОС или SQL Server ни на одном компьютере, и Я НЕ МОГУ вносить изменения в разрешения или олицетворение, и Я НЕ МОГУ использовать руны.

Я знаю, что могу писать приложения на Perl и Java, которые могут подключаться к базе данных SQL Server, используя только эти четыре параметра: имя сервера, имя базы данных, имя пользователя (в форме домен \ пользователь) и пароль.

В C # я пробовал разные вещи вокруг:

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

и попытался установить для интегрированной безопасности значение true и false, но, похоже, ничего не работает. Что я пытаюсь сделать просто невозможно в C #?

Спасибо за любую помощь, Мартин

Ответы [ 7 ]

8 голосов
/ 19 января 2011

У меня была похожая проблема, когда я писал инструмент, который должен был работать на компьютере в одном домене и проходить проверку подлинности на сервере SQL в другом домене, используя доверенное соединение. Все, что я мог найти по этому вопросу, говорило, что это невозможно сделать. Вместо этого вы должны присоединиться к домену, использовать проверку подлинности SQL, принять участие в какой-то главе под названием Kerberos или попросить ваших сетевых парней установить доверительные отношения, чтобы назвать несколько альтернатив.

Дело в том, что я знал, что смогу заставить его работать каким-то образом, используя 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"

Флаг / netonly позволил мне выполнить exe-файл с локальными учетными данными и получить доступ к сети с удаленными учетными данными, я думаю, в любом случае я получил ожидаемый от удаленного сервера набор результатов. Проблема заключалась в том, что команда runas сильно затрудняла отладку приложения, и она плохо пахла.

В конце концов я нашел эту статью в проекте кода , в котором говорилось о проверке подлинности для управления 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();
            }
        }
    }

Чтобы использовать это просто:

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

//Connect to and use SQL server

impersonator.Undo();

Я добавил в метод Undo, иначе объект подражателя имел тенденцию собирать мусор. Я также изменил код для использования LOGON32_LOGON_NEW_CREDENTIALS, но это было сделано, чтобы заставить его работать; Мне все еще нужно полностью понять, что он делает, я чувствую то же самое, что / netonly flag на runas. Я также собираюсь немного сломать конструктор.

4 голосов
/ 13 мая 2010

Бесполезно указывать имя пользователя и пароль в строке подключения, поскольку они подразумевают аутентификацию SQL, а вы уже указали, что SQL Server принимает только аутентификацию Windows.

Если на сервере не разрешена аутентификация SQL, то для подключения only можно использовать аутентификацию Windows, т.е. IntegratedSecurity=true. Это означает, что ваш клиент будет проходить проверку подлинности как учетные данные, выполняющие процесс (или исполняемые в настоящее время в качестве олицетворения).

Чтобы проверка подлинности Windows работала, вам нужно выбрать один из следующих вариантов:

  • Объедините присоединенный компьютер, не относящийся к домену, в домен (это может быть собственный домен!), Который доверяет домену сервера, затем запустите клиентский процесс как учетные данные домена \ пользователя.
  • Использование зеркальных учетных записей NTLM: пара локальных пользователей на клиенте и сервере с одинаковыми именами и паролями.
  • Предоставить как АНОНИМНЫЙ доступ к SQL Server.

Если вы не можете заставить клиентский узел доверять домену сервера и не можете добавлять зеркальные учетные записи NTLM, а администратор SQL Server достаточно здравомыслящий, чтобы не включить ANONYMOUS, тогда вы не сможете подключиться.

2 голосов
/ 22 августа 2010

Как вы правильно сказали, JDBC или Perl на компьютере с Linux могут одновременно подключаться к SQL Server с использованием аутентификации Windows и учетных данных, которые отличаются от данных текущего пользователя. Кстати, то же самое относится и к устройствам Windows CE .

Я думаю, это не проблема C #, а проблема драйвера OLE DB для SQL Server. Я предполагаю, что методы, упомянутые выше, «притворяются машинами Windows, использующими определенные учетные данные» на сетевом уровне; особенность, которой нет в драйвере OLE DB для SQL Server. Таким образом, мое предложение будет искать альтернативный (может быть коммерческий?) Драйвер OLE DB, который может получить доступ к базам данных SQL Server. Хотя я не уверен, что такая вещь существует.

2 голосов
/ 13 мая 2010

Необходимо настроить SQL Server , чтобы разрешить аутентификацию SQL Server, то есть аутентификацию с использованием имени пользователя и пароля.

Вы не можете аутентифицироваться по имени пользователя / паролю домена, как «серверная аутентификация», т.е. указывать имя пользователя / пароль домена напрямую.

Конечно, я могу ошибаться, но я уверен, что это не проблема C # или .NET. Как вы можете войти на SQL Server в вашем приложении на Perl или Java ??

0 голосов
/ 13 мая 2010

Вот пример кода, который я использую для подключения с компьютера, не входящего в домен, с помощью драйвера JTBC JTDS:

Class.forName ( "net.sourceforge.jtds.jdbc.Driver") newInstance (). String url = "jdbc: jtds: sqlserver: // сервер / база данных; домен = домен"; conn = DriverManager.getConnection (url, "пользователь", "пароль");

0 голосов
/ 13 мая 2010
0 голосов
/ 13 мая 2010

Я дам вам ответ Java, с которым я более знаком: я использую драйвер jTDS JDBC с четырьмя параметрами, упомянутыми выше. Приложение Perl, о котором я знаю меньше, но работает на Linux и может подключаться с теми же параметрами. Я не могу изменить SQL Server для поддержки аутентификации SQL.

Чтобы ответить на предложения Ремуса, я не могу сделать ни одну из этих трех вещей, которые он предлагает, и все же приложения Java и Perl могут соединяться. Есть другие идеи?

Спасибо, Мартин

...