我有一个相当奇怪的要求,当我已经冒充他人时,能够模仿用户,使用C#。
我正在编写一个应用程序以允许管理Active Directory用户。此应用程序将为公司中的任何人提供查看和维护自身某些详细信息的功能(其中一些实际上不会保存到Active Directory,但其中一些将保存),以便管理员能够查看和维护有关的详细信息他们的团队,以及人力资源部门能够查看和维护任何人的详细信息。
出于显而易见的原因,我不想针对实时域开发或测试它。我们最近将所有用户从另一个域移植到此域,这意味着我实际上可以在不影响任何内容的情况下对旧域进行测试。但是,为了使我能够这样做,我必须在旧域上模拟我的旧帐户,我在加载应用程序时这样做。
虽然对我来说一切都会正常工作,因为我设置为域管理员,但显然并非所有用户都是域管理员,并且无法在自己的帐户下写入AD,因此我们有另一个专门为此应用程序设置的域管理员用户,每当需要将数据保存到AD时,用户才会被模拟。这在我测试我在虚拟机上设置的Active Directory之前工作得很好,因为我登录到本地域,但是这不允许我在Visual Studio中单步执行代码,因此调试速度很慢,因此我已停止使用该虚拟机并使用此旧域。现在我已经冒充了另一个用户(即我的旧域帐户),然后它尝试模拟域管理员用户失败时出现“System.Security.SecurityException:Access is denied”。例外。这个失败的行只是使用“WindowsIdentity.GetCurrent()。Name”写出一些调试信息。
如果我更改了我的代码,那么我实际上是使用新域管理员而不是旧帐户登录,第一次通过它成功登录(因此凭据是正确的),但是当它通过时并尝试再次执行相同操作以写入AD失败并出现上述异常。因此,我认为尝试进行嵌套模拟一定是个问题。
是否可以进行嵌套模拟?
以下是我正在使用的代码:
private static WindowsImpersonationContext ImpersonateUser(out string result, string sUsername,
string sDomain, string sPassword)
{
// initialize tokens
var pExistingTokenHandle = new IntPtr(0);
var pDuplicateTokenHandle = new IntPtr(0);
// if domain name was blank, assume local machine
if (sDomain == "")
{
sDomain = Environment.MachineName;
}
try
{
result = null;
const int logon32ProviderDefault = 0;
// create token
const int logon32LogonInteractive = 2;
// get handle to token
var bImpersonated = LogonUser(sUsername, sDomain, sPassword,
logon32LogonInteractive,
logon32ProviderDefault,
ref pExistingTokenHandle);
// did impersonation fail?
if (!bImpersonated)
{
var nErrorCode = Marshal.GetLastWin32Error();
result = "LogonUser() failed with error code: " + nErrorCode + "\r\n";
}
// Get identity before impersonation
result += string.Format("Before impersonation: {0}\r\n", WindowsIdentity.GetCurrent().Name);
var bRetVal = DuplicateToken(pExistingTokenHandle, (int)SecurityImpersonationLevel.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (bRetVal)
{
// create new identity using new primary token
var newId = new WindowsIdentity(pDuplicateTokenHandle);
var impersonatedUser = newId.Impersonate();
// check the identity after impersonation
result += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";
return impersonatedUser;
}
else
{
var nErrorCode = Marshal.GetLastWin32Error();
CloseHandle(pExistingTokenHandle); // close existing handle
result += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n";
return null;
}
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
{
CloseHandle(pExistingTokenHandle);
}
if (pDuplicateTokenHandle != IntPtr.Zero)
{
CloseHandle(pDuplicateTokenHandle);
}
}
}
当为嵌套模拟调用失败时,“bImpersonated”实际上是“true”,bRetVal也是如此,这表明它有效,但是当它到达“WindowsIdentity.GetCurrent()。Name”时它失败了例外情况。
我希望这是有道理的,并希望得到任何帮助。