模拟适用于本地共享文件,但不适用于远程文件

Impersonation works with local shared file, but does not work with remote one

我有一个带有 windows 身份验证的 .net/c# 网络应用程序 (web api)。该服务托管在我的本地计算机 IIS 10 上。应用程序池标识设置为我,当前登录 windows 用户。计算机在活动目录域中。

我想使用当前登录到应用程序的帐户访问共享文件。文件具有适当的权限。为此,我使用这样的模拟:

    if (HttpContext.Current.User.Identity is WindowsIdentity windowsIdentity)
       {
           using (windowsIdentity.Impersonate())
           {
                FileStream stream = new FileStream(@"\server\share\file.ext", FileMode.Open, FileAccess.Read);
           }
       }

我使用当前 windows 帐户登录,与在应用程序池身份中设置的相同。这适用于托管应用程序的本地计算机上的共享文件。但不适用于位于另一台计算机上的远程共享文件。另一台计算机也在活动目录域中。

我可以从托管计算机使用 windows 资源管理器或我的浏览器访问共享文件。此外,如果我不模拟用户,.net 会尝试使用应用程序池身份帐户访问共享文件(设置为同一用户,我),本地和远程文件都成功。

它也适用于从 advapi32.dll 的 LogonUser 方法获得的模拟身份。但它需要用户密码,我不想向已经登录到应用程序的用户请求密码。

我做错了什么?

更新:如果共享文件位于主机上,则 windows(事件查看器中的安全选项卡)生成的登录事件会显示正确的用户。如果共享文件位于另一台机器上,则此机器上 windows 生成的登录事件显示匿名用户。所以,帐号不知何故丢失了。

更新 2:如果我在 IIS 上 运行 站点像本地主机(url 中的本地主机),则模拟有效。但是如果我 运行 它使用 ip 或站点名称它停止工作。

更新 3:Wireshark 显示获取委派票证(访问共享文件服务器)的请求失败,错误为 "KRB5KDC_ERR_BADOPTION NT Status: STATUS_NOT_FOUND"。 AD 中允许的应用程序池用户委派。 在 cmd 中执行 Dir 命令时,可以成功检索(wireshark 显示)未委托的同一张票(for cifs/fileshareservername)。似乎是 AD 中的问题。

无法确定您的操作是否有误,但我可以告诉您我为完成非常相似的事情所做的工作。我的 .Net 站点通常没有 WindowsLogin,所以我不得不进行额外的跳转,我认为你可以做同样的事情,只是可能不是最好的答案。

登录时(在我的 membershipProvider 中)我 运行 此代码:

try
{
    if (LogonUser(user,domain,password, [AD_LOGIN], 
                   LOGON32_PROVIDER_DEFAULT, ref handle))
    {
        IntPtr tokenDuplicate = IntPtr.Zero;

       if (DuplicateToken(handle, SecurityImpersonation,
             ref tokenDuplicate) != 0)
       {
          // store off duplicate token here
       }
    }
}
finally
{
    if (handle != IntPtr.Zero)
    {
        CloseHandle(handle);
    }
}

然后当你需要模仿的时候,这样做:

var context = WindowsIdentity.Impersonate(tokenDuplicate);
try
{
    // do your file access here
}
finally
{
    context.Dispose();
}

我必须对那个 tokenDuplicate 变量做一些有趣的转换。它是一个整数值,但指向存储令牌信息的特定内存地址。只要您登录,它就会保持良好状态。

为什么你不能直接根据你的身份进行冒充,不知道。我只知道使用令牌对我有用,这就是我获取可用于模拟的令牌的方法。

它开始使用以下设置为我工作。

IIS:

  1. 应用程序池标识设置为特定用户(比方说 IISUser)。
  2. Windows 为 IIS 站点启用身份验证。启用内核模式(重要!)。

Active Directory 中正在发生所有其他魔术:

  1. 具有共享文件的计算机有一个 SPN:cifs/%computer_name%。
  2. 托管计算机(安装了 IIS 的计算机)受委托信任。委派选项卡 -> 信任此计算机仅委派给指定的服务 -> 使用任何身份验证协议。然后是第 1 项中的 select SPN。重要提示:您应该 select 计算机 SPN,而不是 IISUser SPN。
  3. IISUser 被信任用于从项目 1 委派 SPN。