Ну, кажется, что это может быть сделано в конце концов.Я обнаружил следующую ссылку , и это привело меня к пониманию, что моей основной проблемой было неправильное использование параметра 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
}