У меня была похожая проблема, когда я писал инструмент, который должен был работать на компьютере в одном домене и проходить проверку подлинности на сервере 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. Я также собираюсь немного сломать конструктор.