【发布时间】:2015-02-19 02:09:33
【问题描述】:
我正在处理一个令人讨厌的问题,让我准备好撕掉我的头发。我有一个 C# 控制台应用程序,它使用 Microsoft 的 HttpListener 类来侦听 Web 请求。这个想法是控制台应用程序作为 UserAccountA(低权限)在后台运行。 UserAccountB(管理员等)出现,通过侦听器访问网页,并假冒他或她的身份。 IIS 或 WCF 所做的事情相同。我相信我在 Windows 7 上运行过这个,但现在我在 Windows 8.1 上,它又失败了。也许我从来没有开始,或者也许这是一个新的转折。
如果我通过 Visual Studio 运行程序,我可以使用 Internet Explorer 11 访问它。出于某种原因,它要求我输入本地凭据。我假设这与 IE11 的开箱即用行为有关。一旦我输入它,它就会接受它。我的代码是这样开始的:
protected virtual void Listen(object o)
{
HttpListener h = (HttpListener)o;
while (h.IsListening && (this.Disposed == false))
{
IAsyncResult Result = null;
Result = h.BeginGetContext(new AsyncCallback(this.ListenerCallback), h);
Result.AsyncWaitHandle.WaitOne();
}
}
而且是这样捡起来的(略):
protected virtual void ListenerCallback(IAsyncResult Result)
{
HttpListener h = (HttpListener)Result.AsyncState;
HttpListenerContext context = null;
System.Security.Principal.WindowsIdentity identity = null;
context = h.EndGetContext(Result);
identity = (System.Security.Principal.WindowsIdentity)context.User.Identity;
using (System.Security.Principal.WindowsImpersonationContext wic = identity.Impersonate())
{
//method call to process request, under impersonation
}
}
在使用两个不同的帐户(一个用于托管,一个用于访问)时,我已逐步完成此代码。我已经使用此语句进行了验证:
system.security.principal.windowsidentity.getcurrent().name
当前身份确实转换。侦听器配置为使用 NTLM AuthenticationScheme 启动。
我想复杂的部分在于模拟期间调用的方法。我们正在做一些抽象,但让我指出失败的部分。在这种情况下,我们使用 SSPI 连接到 SQL Server - 因此模拟的全部目的是获取客户端的现有登录并优雅地将它们导入 SQL Server。同样,现在,这对一台计算机来说都是本地的。它甚至不在活动目录域中。一切都是本地的,具有本地帐户。开头是这样的:
System.Data.Common.DbProviderFactory fact = null;
if (UseSql())
{
fact = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
}
没什么大不了的。我们在另一个项目中不断使用提供程序工厂,没有任何问题(但这只是一个常规的 WPF 应用程序,没有这样的)。在此之后,我们将使用 SSPI 属性设置 SQL 登录字符串。但我们甚至没有做到这一点。这正是它失败的地方,并带有以下消息:
“System.IO.FileLoadException”类型的第一次机会异常 发生在 mscorlib.dll 中
附加信息:无法加载文件或程序集 'System.Data.OracleClient,版本=4.0.0.0,文化=中性, > PublicKeyToken=b77a5c561934e089' 或其依赖项之一。要么 未提供所需的模拟级别,或提供的 模拟级别无效。 (HRESULT 异常:0x80070542)
http://i854.photobucket.com/albums/ab103/srVincentVega/error7_zpsmb1xqrp0.png
我们根本没有使用 Oracle,我假设这只是它在尝试打开 DbProviderFactory 时的第一件事。对我来说,关键是模仿级别的东西。在这个特定的实验中,两个帐户(A 和 B)都是本地管理员。我已经通过本地安全策略确保他们可以在登录后模拟帐户。如果我查看我的事件日志,模拟似乎确实有效......
分配给新登录的特殊权限。
主题:安全 ID:
pc1\userA
账户名:userA
帐户域:pc1 登录 ID:0xC4D0F3F
特权:
SeSecurityPrivilege
SeTakeOwnershipPrivilege
SeLoadDriverPrivilege
SeBackupPrivilege
SeRestorePrivilege
SeDebugPrivilege
SeSystemEnvironmentPrivilege
SeImpersonatePrivilege
我在这里尝试了很多变化,以至于我开始妨碍我自己的分析。我基本上回到了第一方,不知道如何解决这个问题。有没有人有任何建议或提示?这似乎应该是一件非常简单的事情。我不知道为什么我有这么多麻烦。也许我只需要放弃使用 DbProviderFactory 并使用 OleDb 或其他什么。但我还没有确认我可以在模拟后在运行时加载任何库。也许这是要做的事情。但是,我将非常感谢您的帮助。
谢谢,
约翰
最后一件事,这里是复制步骤:
在您的计算机上创建辅助用户。登录以创建配置文件。像往常一样注销并重新登录。以该次要用户身份运行 Visual Studio(有几种方法可以做到这一点,shift + 右键单击 VS 图标),并在其中使用此框架创建一个 C# 控制台应用程序:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using (HttpListener h = new HttpListener())
{
h.Prefixes.Add("http://+:8090/");
h.AuthenticationSchemes = AuthenticationSchemes.Ntlm;
h.Start();
Console.WriteLine("Running");
HttpListenerContext context = h.GetContext();
System.Security.Principal.WindowsIdentity identity = null;
identity = (System.Security.Principal.WindowsIdentity)context.User.Identity;
using (System.Security.Principal.WindowsImpersonationContext wic = identity.Impersonate())
{
System.Data.Common.DbProviderFactory fact = null;
fact = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
}
Console.ReadLine();
h.Stop();
}
}
}
}
调试/运行控制台应用程序。只需调用 Internet Explorer(普通版,使用您的主帐户)并访问该 URL (http://machinename:8090)。发生异常
http://i854.photobucket.com/albums/ab103/srVincentVega/error8_zpsilkay0bl.png
【问题讨论】:
-
根据您执行此操作的方式,您可能需要添加本地规则来侦听 8090 等端口。您可以在提升的命令提示符下执行此操作:netsh http add urlacl url=http ://+:8090/user=(SecondaryAcctName)
标签: c# visual-studio impersonation httplistener