Parallel .ForEach () changes the impersonation context

Today, we deployed our new ASP.NET application to the server, and soon we realized that there was a strange security issue that caused the application to crash. This is an internal application, and we use impersonation to control user access to resources. However, the application throws a "Denied access" exception when the user gains access to a folder over which they have full control.

The exception was actually an AggregateException and was thrown into a method that uses Parallel.ForEach to enumerate through the list and inside the body, it tries to access the folder, but at the moment the impersonation context is changing and the workflow works as an application pool identifier that does not have access to the folder is therefore an exception.

To confirm this, I looked at the process identifier before and inside the body of 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); }); 

When I run the application, this is what prints out:

 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) 

As you can see, some threads run as an impersonator identifier, and some as an application pool (in this case LocalSystem ), and there seems to be no template. The previous frame in the Call Stack window also refers to the unmanaged kernel32.dll , which makes me think that the CLR does not check the context before it is delegated to the OS.

Any idea why this is happening? Is this a known issue / bug?

+5
source share
2 answers

Unlike the Task class, Parallel does not seem to capture the ExecutionContext you are currently working on (which in turn captures the SecurityContext that contains the WindowsIdentity ). It uses one available in the current topic.

You must explicitly write down the desired context:

 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); } }); 
+3
source

The whole concept of impersonation in Windows is the concept of flow. You see, when a new thread is created, it inherits the process privilege token. But threads, unlike processes, also have an impersonation marker. When you call WindowsIdentity.Impersonate (token), you set the impersonation token in the calling thread.

Also, when you call Impersonate, you set the pointer to the primary stream pointer, pointing to the impersonation token instead of the main process token, which is the default value.

A little more understanding and knowledge in WinAPI will lead you to understand what happened in your service - this is the expected behavior.

0
source

Source: https://habr.com/ru/post/1203495/


All Articles