Аутентификация на ненадежном домене из приложения WPF - PullRequest
0 голосов
/ 15 июня 2011

У меня есть приложение WPF, которому требуется доступ к базе данных SQL Server 2008 R2.База данных защищена с использованием активного каталога.Приложение отлично работает на рабочих станциях, которые подключены к домену и где пользователь успешно вошел в систему.

Теперь мне нужно иметь возможность запускать одно и то же приложение на рабочих станциях, подключенных к другому домену.К сожалению, этот новый домен контролируется SBS, и поэтому я не могу установить доверительные отношения между ними.

По сути, мне (как мне кажется) нужно средство, позволяющее пользователю вводить учетные данные, которые былиустановить на домене, где размещается сервер базы данных (имя пользователя и пароль), а затем выдать себя за этого пользователя при подключении к серверу базы данных.

Я пробовал пример Microsoft с использованием LogonUser, LOGON32_PROVIDER_DEFAULT & LOGON32_LOGON_INTERACTIVE, но это не похожеделать то, что я хочу - вместо этого жаловаться, что я не могу войти в систему, поскольку у рабочей станции, на которой я работаю, нет учетной записи домена.

У кого-нибудь есть альтернативные предложения?

Ответы [ 3 ]

1 голос
/ 15 июня 2011

С НАСТРОЙКОЙ ВАШЕГО ТОКА

The database is secured using active directory

Полагаю, вы имеете в виду, что ваше SQL-соединение использует проверку подлинности Windows. В любом случае, происходит немного больше, чем вы, возможно, понимаете. Если вы используете «активный каталог» для аутентификации, могу поспорить, что вы используете Kerberos для аутентификации Windows (это не только ваш тип аутентификации, но и тип ваших учетных данных). В статье, на которую я ссылаюсь, объясняется разница между Kerberos и NTLM для SQL Server 2005, но она одинакова для 2008 R2.

К сожалению, без доверительных отношений между доменами, не имеет значения, если вы успешно выдаете себя за пользователя в домене, где размещена база данных, вы не сможете подключиться (как вы видите). Вам нужны эти доверительные отношения .

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

АЛЬТЕРНАТИВНАЯ НАСТРОЙКА

Если вы не хотите использовать аутентификацию SQL (мне не нравится упаковывать учетные данные с моими приложениями), я рекомендую вам разделить ваши операции с базами данных в более сервис-ориентированную архитектуру. Таким образом, фактическая работа SQL будет выполняться в службе WCF (которая размещается в том же домене, что и ваша база данных, и олицетворяет идентификатор службы), и ваше приложение просто запросит службу. Затем вы можете использовать NTLM для защиты веб-службы, чтобы по-прежнему использовать проверку подлинности Windows. Таким образом, вы все еще можете проверить, кто является запрашивающим пользователем, и полагаться на свои собственные базовые структуры безопасности (то есть простые таблицы), чтобы разрешить использование.

Дайте мне знать, если это не имеет смысла для вас или вам нужны дополнительные разъяснения.

0 голосов
/ 16 июня 2011

Ну, кажется, что это может быть сделано в конце концов.Я обнаружил следующую ссылку , и это привело меня к пониманию, что моей основной проблемой было неправильное использование параметра LOGON32_LOGON_INTERACTIVE для вызова API LogonUser (это должен был быть LOGON32_LOGON_NEWCREDENTIALS).

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

static void Main (string)[] args) {

SafeTokenHandle safeTokenHandle;

try {

    string userName = @"*****", domainName = @"*****", password = @"*****";
    bool returnValue = NativeMethods.LogonUser(userName, domainName, password, 
        NativeMethods.LogonType.NewCredentials, NativeMethods.LogonProvider.Default, out safeTokenHandle);

    if (false == returnValue) {
        int ret = Marshal.GetLastWin32Error();
        Console.WriteLine("LogonUser failed with error code : {0}", ret);
        throw new Win32Exception(ret);
    }

    using (safeTokenHandle) {

        WindowsIdentity windowsIdentity = new WindowsIdentity(safeTokenHandle.DangerousGetHandle());
        using (WindowsImpersonationContext impersonationContext = windowsIdentity.Impersonate()) {

            using (DataTable table = new DataTable()) {
                using (SqlDataAdapter adapter = new SqlDataAdapter()) {
                    using (adapter.SelectCommand = new SqlCommand(@"select * from dbo.MyTable")) {
                        adapter.SelectCommand.CommandType = CommandType.Text;
                        using (adapter.SelectCommand.Connection = new SqlConnection(@"Data Source=Server;Initial Catalog=Database;Integrated Security=Yes")) {
                            adapter.SelectCommand.Connection.Open();
                            adapter.Fill(table);
                        }
                    }
                }

                Console.WriteLine(string.Format(@"{0} Rows retrieved.", table.Rows.Count));

            }

        }

    }

}
catch (Exception ex) {
    Console.WriteLine("Exception occurred. " + ex.Message);
}

Конечно, нужно привести в порядок, и мне нужно попросить пользователя ввести его учетные данные (нет способа убедить меня в жестких кодах), но в принципе это работает(за исключением анонимизации).

Надеюсь, это поможет кому-нибудь еще когда-нибудь.

О, и вам также понадобится следующее ...

public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid {

    private SafeTokenHandle() : base(true) {
    }

    protected override bool ReleaseHandle() {
        return NativeMethods.CloseHandle(handle);
    }

}

[DllImport(@"kernel32.dll")]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(
    IntPtr handle);

[DllImport(@"advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern bool LogonUser(
    String lpszUsername,
    String lpszDomain,
    String lpszPassword,
    LogonType dwLogonType,
    LogonProvider dwLogonProvider,
    out SafeTokenHandle phToken);

public enum LogonType {
    Interactive = 2,
    Network = 3,
    Batch = 4,
    Service = 5,
    Unlock = 7,
    NetworkClearText = 8,
    NewCredentials = 9
}

public enum LogonProvider {
    Default = 0,
    WinNT35 = 1,
    WinNT40 = 2,
    WinNT50 = 3
}
0 голосов
/ 15 июня 2011

У меня есть предложение ... но я не думаю, что оно вам понравится.

Использовать проверку подлинности SQL вместо встроенной.

У меня была похожая проблема, и после проработки - оказалось, что действительно не было способа сделать это. Смотрите здесь мой пост на dba.stackexchange.com

Если использование SQL-аутентификации не является опцией, все равно «может» существовать способ с помощью клейкой ленты / освобождения провода / общего хакера, но вам, вероятно, придется перенести вопрос на один из форумов администратора сервера а не StackOverflow - так как это больше не вопрос программирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...