模拟适用于本地共享文件,但不适用于远程文件
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:
- 应用程序池标识设置为特定用户(比方说 IISUser)。
- Windows 为 IIS 站点启用身份验证。启用内核模式(重要!)。
Active Directory 中正在发生所有其他魔术:
- 具有共享文件的计算机有一个 SPN:cifs/%computer_name%。
- 托管计算机(安装了 IIS 的计算机)受委托信任。委派选项卡 -> 信任此计算机仅委派给指定的服务 -> 使用任何身份验证协议。然后是第 1 项中的 select SPN。重要提示:您应该 select 计算机 SPN,而不是 IISUser SPN。
- IISUser 被信任用于从项目 1 委派 SPN。
我有一个带有 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:
- 应用程序池标识设置为特定用户(比方说 IISUser)。
- Windows 为 IIS 站点启用身份验证。启用内核模式(重要!)。
Active Directory 中正在发生所有其他魔术:
- 具有共享文件的计算机有一个 SPN:cifs/%computer_name%。
- 托管计算机(安装了 IIS 的计算机)受委托信任。委派选项卡 -> 信任此计算机仅委派给指定的服务 -> 使用任何身份验证协议。然后是第 1 项中的 select SPN。重要提示:您应该 select 计算机 SPN,而不是 IISUser SPN。
- IISUser 被信任用于从项目 1 委派 SPN。