我有一个类似的问题,我正在编写一个工具,该工具需要在一个域的机器上运行,并使用受信任的连接在另一个域的 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,这是进行模拟的主要类:
使用系统;
使用 System.Runtime.InteropServices;// DLL导入
使用 System.Security.Principal;// WindowsImpersonationContext
命名空间 TestApp
{
类模仿者
{
// 组类型枚举
枚举 SECURITY_IMPERSONATION_LEVEL : int
{
安全匿名 = 0,
安全识别 = 1,
安全模拟 = 2,
安全委托 = 3
}
// 获取用户令牌
[DllImport("advapi32.dll", SetLastError = true)]
静态外部布尔登录用户(字符串 pszUsername,字符串 pszDomain,字符串 pszPassword,
int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
// 关闭由 LogonUser 返回的张开的手
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
extern static bool CloseHandle(IntPtr 句柄);
// 创建重复的令牌句柄
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
extern static bool DuplicateToken(IntPtr ExistingTokenHandle,
int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
WindowsImpersonationContext 新用户;
///
/// 尝试模拟用户。如果成功,返回
/// 新用户身份的 WindowsImpersonationContext。
///
/// 要模拟的用户名
/// 登录域
/// 用户登录密码
///
public Impersonator(字符串 sUsername,字符串 sDomain,字符串 sPassword)
{
// 初始化令牌
IntPtr pExistingTokenHandle = new IntPtr(0);
IntPtr pDuplicateTokenHandle = new IntPtr(0);
pExistingTokenHandle = IntPtr.Zero;
pDuplicateTokenHandle = IntPtr.Zero;
// 如果域名为空,则假定为本地机器
if (sDomain == "")
sDomain = System.Environment.MachineName;
尝试
{
常量 int LOGON32_PROVIDER_DEFAULT = 0;
// 创建令牌
// 常量 int LOGON32_LOGON_INTERACTIVE = 2;
常量 int LOGON32_LOGON_NEW_CREDENTIALS = 9;
//const int SecurityImpersonation = 2;
// 获取令牌句柄
bool bImpersonated = LogonUser(sUsername, sDomain, sPassword,
LOGON32_LOGON_NEW_CREDENTIALS,LOGON32_PROVIDER_DEFAULT,参考 pExistingTokenHandle);
// 模拟失败了吗?
if (false == bImpersonated)
{
int nErrorCode = Marshal.GetLastWin32Error();
// 显示 LogonUser 失败的原因
throw new ApplicationException("LogonUser() 失败,错误代码:" + nErrorCode);
}
bool bRetVal = DuplicateToken(pExistingTokenHandle, (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref pDuplicateTokenHandle);
// DuplicateToken 失败了吗?
如果(假 == bRetVal)
{
int nErrorCode = Marshal.GetLastWin32Error();
关闭句柄(pExistingTokenHandle);// 关闭现有句柄
// 显示 DuplicateToken 失败的原因
throw new ApplicationException("DuplicateToken() 失败,错误代码:" + nErrorCode);
}
别的
{
// 使用新的主令牌创建新的身份
WindowsIdentity newId = new WindowsIdentity(pDuplicateTokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
新用户 = 模拟用户;
}
}
最后
{
//关闭句柄
if (pExistingTokenHandle != IntPtr.Zero)
关闭句柄(pExistingTokenHandle);
if (pDuplicateTokenHandle != IntPtr.Zero)
关闭句柄(pDuplicateTokenHandle);
}
}
公共无效撤消()
{
新用户.Undo();
}
}
}
要使用它:
Impersonator impersonator = new Impersonator("username", "domain", "password");
//Connect to and use SQL server
impersonator.Undo();
我在 Undo 方法中添加,否则模拟对象往往会被垃圾收集。我还更改了代码以使用 LOGON32_LOGON_NEW_CREDENTIALS ,但这是一个戳并运行以使其工作;我仍然需要完全了解它的作用,我感觉它与 runas 上的 /netonly 标志相同。我还将稍微分解构造函数。