0

当我已经使用 C# 模拟另一个用户时,我有一个相当奇怪的要求是能够模拟一个用户。

我正在编写一个允许管理 Active Directory 用户的应用程序。该应用程序将使公司中的任何人都能够查看和维护有关他们自己的某些详细信息(其中一些实际上不会保存到 Active Directory,但其中一些会),以便管理人员能够查看和维护有关他们的详细信息他们的团队,并让 HR 能够查看和维护任何人的详细信息。

出于显而易见的原因,我不想针对实时域进行开发或测试。我们最近将所有用户从另一个域移植到该域,这意味着我实际上可以针对旧域进行测试而不会影响任何事情。但是,为了让我能够做到这一点,我必须在旧域上模拟我的旧帐户,我在加载应用程序时会这样做。

虽然对我来说一切都会很好,因为我设置为域管理员,但显然并非所有用户都是域管理员,并且无法在自己的帐户下写入 AD,因此我们有另一个域管理员专门为此应用程序的用户设置,每当需要将数据保存到模拟该用户的 AD 时。这在我针对我在虚拟机上设置的 Active Directory 进行测试之前工作得很好,因为我登录到本地域,但是这不允许我在 Visual Studio 中单步执行代码,所以调试很慢,因此我已经停止使用该虚拟机并正在使用这个旧域。现在我已经在模拟另一个用户(即我的旧域帐户),当它尝试模拟域管理员用户时,它失败并显示“System.

如果我更改我的代码,所以我实际上是使用新的域管理员而不是我的旧帐户登录,它第一次通过它成功登录(所以凭据是正确的),但是当它通过并尝试再次执行相同操作以写入 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”实际上是“真”,bRetVal 也是如此,这表明它有效,但是当它到达“WindowsIdentity.GetCurrent().Name”时,它会失败,但出现上述异常。

我希望这是有道理的,并会感谢任何帮助。

4

0 回答 0