c# - Parallel.ForEach() 更改模拟上下文

标签 c# .net task-parallel-library impersonation parallel.foreach

今天,我们将新创建的 ASP.NET 应用程序部署到服务器,很快我们就意识到存在一个奇怪的安全相关问题,该问题导致应用程序崩溃。这是一个内部应用程序,我们使用模拟来管理用户访问资源的方式。但是,当用户尝试访问他们可以完全控制的文件夹时,应用程序会抛出“拒绝访问”异常。

该异常实际上是一个 AggregateException 并被抛出到一个使用 Parallel.ForEach 的方法中以枚举列表和主体内部,它尝试访问文件夹,但此时模拟上下文发生更改,工作线程作为应用程序池的身份运行,它无权访问该文件夹,因此出现异常。

为了确认这一点,我查看了 Parallel.ForEach 主体之前和内部的进程标识:

string before = WindowsIdentity.GetCurrent().Name;
Debug.WriteLine("Before Loop: {0}", before);

Parallel.ForEach(myList, currentItem =>
{
    string inside = WindowsIdentity.GetCurrent().Name;
    Debug.WriteLine("Inside Loop: {0} (Worker Thread {1})", inside, Thread.CurrentThread.ManagedThreadId);
});

当我运行该应用程序时,打印出以下内容:

Before Loop: MyDomain\ImpersonatedUser

Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 8)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 6)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)
Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 9)
Inside Loop: NT AUTHORITY\SYSTEM (Worker Thread 10)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 6)
Inside Loop: MyDomain\ImpersonatedUser (Worker Thread 7)

如您所见,一些线程作为模拟身份运行,一些线程作为应用程序池(在本例中为 LocalSystem)运行,似乎没有任何模式。 Call Stack 窗口中的前一帧也转到非托管 kernel32.dll,这让我觉得 CLR 在将上下文委托(delegate)给操作系统之前没有验证上下文。

知道为什么会这样吗?这是一个已知问题/错误吗?

最佳答案

Task 类不同,Parallel 似乎没有捕获您当前正在运行的 ExecutionContext(它反过来捕获SecurityContext 包含 WindowsIdentity)。它使用当前线程中可用的那个。

您必须明确捕获所需的上下文:

IntPtr token = WindowsIdentity.GetCurrent().Token;

Parallel.ForEach(myList, currentItem =>
{
   using (WindowsIdentity.Impersonate(token))
   {
      string inside = WindowsIdentity.GetCurrent().Name;
      Debug.WriteLine("Inside Loop: {0} (Worker Thread {1})", inside, Thread.CurrentThread.ManagedThreadId);
   }
});

关于c# - Parallel.ForEach() 更改模拟上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26065155/

相关文章:

c# - 如何在 C# 或 F# 中使用 Travis-CI

c# - 如何使用 dll 作为不同机器的加载项?

c# - 为什么我的 AsOrdered PLINQ 查询比我的无序查询更快

c# - 使用 SmtpClient 时为 "The operations timed out"

c# - 我将如何编写自己的FirstOrDefaultAsync()方法

c# - 何时使用 TaskCreationOptions.LongRunning?

c# - 两个 ListBox 一个 ScrollViewer

c# - 覆盖子类中的通用 IEnumerable 接口(interface)

c# - 使用正则表达式从字符串中解析字符串

c# - Parallel.Invoke - 动态创建更多 'threads'