WPF & Thread.CurrentPrincipal
-
Wednesday, January 31, 2007 1:29 AMIn a method which is attached to the loaded event of a window I am setting the thread.currentPrincipal to a custom principal object which I manually create. If i try to access the same thread.currentPrincipal in a method which is attached to a button click event the thread.currentPrincipal in this click method is automatically set back to a generic principal. Why? In retrospect if I set the thread.currentPrincipal to my custom principal in one button and access it from another button its fine and is never reset to a generic principal... Anyone have any idea whats going on?
Answers
-
Thursday, February 01, 2007 11:42 AM
It's not the problem with threading, it's the problem with the RBS implementation of CLR. the documentation says you can assign your custom principal object using AppDomain.SetThreadPrincipal() method or Thread.CurrentPrincipal property, but it seems only the AppDomain.SetThreadPrincipal() method can do the trick here, try to set your custom principal objects using this method.
Sheva -
Thursday, February 01, 2007 6:57 PM
Actually, you are encountering an intentional feature of WPF. The Dispatcher is the central pump that keeps things moving in the application (technically, each thread has its own Dispatcher). It serves as a central queue of things that need to be done by the thread. Any one can add work to this queue - which poses a security risk. The Dispatcher is implemented in one of our system DLLs (installed in the GAC with full trust), and it fetches the next thing to do off the queue of pending work and executes it. This means that it would be possible for someone to post a work item to do something that they don't have permission to do, and trick the system into doing it for them. But wait you say, the Dispatcher simply calls a method, and that method is probably implemented by the poster, so code-access-security will catch the elevation. However, there remains an exploit where an untrusted caller can create a delegate to a method in a trusted DLL, and then the call stack looks entirely trusted by the time we get around to executing it.
This is a general problem with asynchronous programming - examinging the stack at the point of executing a delegate does not explain the stack at the point that the delegate was posted. We chose to be cautious - when anyone posts work to the queue, we snapshot their "execution context", then we apply this execution context when we eventually do the work. This prevents the work from being able to do anything that it wasn't able to do in the beginning when it posted the work.
However, this also means that the work item can't affect the "execution context" of other work items. When we are done with executing a work item, we discard its old "execution context", since it wasn't current anyways. The "execution context" contains things like the impersonation token.
The work around you noted involves changing global state in the AppDomain. This is obviously a method that will demand the appropriate permissions, and the infrastructure I just discussed ensures that for you to succeed in calling this, you really did have the right permissions. However, since you changed global state, it is not part of the thread's "execution context" and so it doesn't get discarded at the end.
All Replies
-
Wednesday, January 31, 2007 6:24 PMIs this perhaps some type of bug?
-
Wednesday, January 31, 2007 7:53 PMModerator
The only thing that I can think of is that your Loaded event handler is being called on a thread separate from the UI. However your button click handler is definitely being called from the UI directly. This is the reason for the two different results.
One fix is to use the Dispatcher to make sure that you are definitely setting the CurrentPrincipal on the correct thread.
-
Wednesday, January 31, 2007 9:01 PMI thought the same thing, but looking at the call stack it would appear everything is working on the same thread and since the loaded event is being fired from the UI it would make sense that the loaded event call is on the same thread as the UI thread. I am using a work around by setting a global variable to the principal and resetting the principal each time its not of type customPrincipal, but this just doesn't seem right. Any MS guys care to take a jab at this one?
-
Thursday, February 01, 2007 6:03 AMModerator
I'm no threading expert...so I figured I'd jump in and look (and learn.)
I'm seeing the same problem...I confirm via this.Dispatcher.Thread and Thread.CurrentThread that the same thread (as expected) is calling the loaded and click event.
This sounds like a question for Dwayne...
Using reflector, I look at the implementation of Thread.CurrentPrincipal...it sheds no new light:
public static IPrincipal CurrentPrincipal { get { lock (Thread.CurrentThread) { IPrincipal principal1 = CallContext.Principal; if (principal1 == null) { principal1 = Thread.GetDomain().GetThreadPrincipal(); CallContext.Principal = principal1; } return principal1; } } [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.ControlPrincipal)] set { CallContext.Principal = value; } }
I'll see if Dwayne or others can answer...
Thanks, Rob Relyea
Program Manager, WPF Team
http://rrelyea.spaces.live.com -
Thursday, February 01, 2007 11:42 AM
It's not the problem with threading, it's the problem with the RBS implementation of CLR. the documentation says you can assign your custom principal object using AppDomain.SetThreadPrincipal() method or Thread.CurrentPrincipal property, but it seems only the AppDomain.SetThreadPrincipal() method can do the trick here, try to set your custom principal objects using this method.
Sheva -
Thursday, February 01, 2007 5:37 PMThis worked perfectly, thank you!
On a side note it would be interesting to know WHY the currentPrincipal is reset when using thread.CurrentPrincipal instead of AppDomain.SetThreadPrincipal().
Thanks again! -
Thursday, February 01, 2007 6:57 PM
Actually, you are encountering an intentional feature of WPF. The Dispatcher is the central pump that keeps things moving in the application (technically, each thread has its own Dispatcher). It serves as a central queue of things that need to be done by the thread. Any one can add work to this queue - which poses a security risk. The Dispatcher is implemented in one of our system DLLs (installed in the GAC with full trust), and it fetches the next thing to do off the queue of pending work and executes it. This means that it would be possible for someone to post a work item to do something that they don't have permission to do, and trick the system into doing it for them. But wait you say, the Dispatcher simply calls a method, and that method is probably implemented by the poster, so code-access-security will catch the elevation. However, there remains an exploit where an untrusted caller can create a delegate to a method in a trusted DLL, and then the call stack looks entirely trusted by the time we get around to executing it.
This is a general problem with asynchronous programming - examinging the stack at the point of executing a delegate does not explain the stack at the point that the delegate was posted. We chose to be cautious - when anyone posts work to the queue, we snapshot their "execution context", then we apply this execution context when we eventually do the work. This prevents the work from being able to do anything that it wasn't able to do in the beginning when it posted the work.
However, this also means that the work item can't affect the "execution context" of other work items. When we are done with executing a work item, we discard its old "execution context", since it wasn't current anyways. The "execution context" contains things like the impersonation token.
The work around you noted involves changing global state in the AppDomain. This is obviously a method that will demand the appropriate permissions, and the infrastructure I just discussed ensures that for you to succeed in calling this, you really did have the right permissions. However, since you changed global state, it is not part of the thread's "execution context" and so it doesn't get discarded at the end.
-
Thursday, February 01, 2007 7:40 PMModeratorSo basically Thread.CurrentPrincipal is more like StackFrame.CurrentPrincipal (if there were a CLR class representing your current stack). I guess that would be useful for when you want to send the Principal to an external process via Remoting or ADO. Pretty sweet!
-
Sunday, February 04, 2007 10:07 AMI have a question to ask:
From my understanding and discovery, WPF and Windows Forms deal with message queue and the work items posted into it quite differently. In Windows Forms, the ExecutionContext will get transfered only if the work items is posted from a thread rather than the window thread, but in WPF, the ExecutionContext will get transfered whenever a work item is posted. my question is why your guys choose to implement the WPF message pump this way?
ya know if you implemented the code which is mentioned in this forum thread using Windows Forms, you ain't get such kinda weird problem.
Sheva -
Friday, March 23, 2007 9:40 AMCould you please specify what exactly you mean with the term "execution context".
We have the strange situation that our client calling an impesonating WCF web service fails to authenticate at the server with the local Kerberos credentials. This happens just when the WPF dispatcher is in the call stack; it works perfectly when calling from the constructor of the Application instance, or from non-WPF clients.
The local Thread.CurrentPrinicpal points to an empty non-authenticated principal (in any of the above cases), but setting it to the current users windows principal (which is valid and authenticated in all cases) does not work, neither with Thread.CurrentPrincipal nor with AppDomain.SetThreadPrincipal().
Any ideas why the authentication fails when called from WPF dispatcher? -
Friday, March 23, 2007 1:24 PMExecutionContext is the thing which wraps all the infomation about a particular thread of execution.
As to your question, try if making a call to ExecutionContext.SuppressFlow() can help you a bit.
Sheva -
Wednesday, March 28, 2007 8:38 AM
Dear Zouh Yong,
thanks for your reply to kunom's post. I work with kunom and hence share the same problem ;-)
Calling ExecutionContext.SuppressFlow() in the App's main or calling it just before the WCF call, i.e. in the button click event handler, didn't help.
Any other hints why impersonation does not work when calling the WCF service from within a WPF button click event handler?
Matthew Lebo wrote: 'This worked perfectly, thank you! '
Dear Matthew,
what exactly did you do to solve your problem?
Where in the WPF app did you make which calls?
We have tried so many things(see kunom's and my posts above) but had no success.
Thanks for your help
clw
- Proposed As Answer by odanvin Thursday, January 07, 2010 8:47 AM
-
Wednesday, March 28, 2007 8:45 AM
Matthew Lebo wrote: 'This worked perfectly, thank you! '
Dear Matthew,
what exactly did you do to solve your problem?
Where in the WPF app did you make which calls?
We have tried so many things(see kunom's and my posts above) but had no success.
Thanks for your help
clw
-
Tuesday, December 01, 2009 12:16 PMThank you guys for all your help!!
Shimmy -
Thursday, January 07, 2010 9:03 AM
I know this it is too late but I put some answers here:
1. Set your custom principal when your application starts with the following line of code:
AppDomain.CurrentDomain.SetThreadPrincipal(principal);
2. Declare the following delegate:
Func<IPrincipal> CurrentPrincipal = () => System.Threading.Thread.CurrentPrincipal;3. Use the Dispatcher as below in order to retrieve the current principal:
var principal = Dispatcher.Invoke(CurrentPrincipal);
An easier option is to set the principal policy and the your custom principal when your application starts with the following lines of code:
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
AppDomain.CurrentDomain.SetThreadPrincipal(principal);
Hoping it will help others...
Olivier- Proposed As Answer by odanvin Thursday, January 07, 2010 9:03 AM

