Don't even try it
You can always set the current thread's principal by calling Thread.CurrentPrincipal. So why can't you just set this on the UI thread each time the user logs in? This trick will not work because the .NET framework captures the execution context (i.e. credentials and other stuff) every time something is dispatched to the UI thread. It then restores that execution context when the message is being handled, and throws away the context when it's done. In other words you can set the principal, but it will be thrown away before the next UI event. .NET does this because it could be a potential security flaw. What if someone handled a UI event in your application and decided to post some work to be done that you didn't want them to have permission to do? Trapping the execution context keeps the security of the code that posts the work, the same as the code that executes the work.
My Solution
There are many solutions to this problem, and coming up with them is not hard. I just thought I'd share one that you might find elegant. The idea is to store the IPrincipal of the logged in user in your own class, and set the current thread's principal before making any calls that require that authentication. This sounds like a pain, but it doesn't have to be. You can setup an IDisposable object that when created, sets the current thread's IPrincipal and then restores the previous value when the object is disposed of.
public class ClientSecurityContext { public static IPrincipal CurrentPrincipal { get; set; } public static IDisposable CreateSecurityContext() { // // Save a copy of the previous IPrincipal so we // can restore it when the caller is finished. // IPrincipal previous = Thread.CurrentPrincipal; // // Set the current thread's principal. // Thread.CurrentPrincipal = CurrentPrincipal; // // Return a notifier that will call the action // when the caller disposes of it. This will be // used to restore the previous IPrinicpal back // on the current thread. // return new DisposeNotifier( () => Thread.CurrentPrincipal = previous); } }
The above code makes use of a handy DisposeNotifier object that calls a delegate when it's disposed of. It's really just my laziness in creating a special class just for this purpose. You can see how a call using this would look in action.
private string[] GetEmployeesUsingService() { using (ClientSecurityContext.CreateSecurityContext()) { // // This is where you would make a call that // requires a particular IPrincipal. // return new string[] { Thread.CurrentPrincipal.Identity.Name, "Ben Bernanke", "Tim Geithner" }; } }
Download the sample project here if you're needing to support something like this.
Subscribe to:
Post Comments (Atom)
I see you still Phongize your code (as do I).
ReplyDelete- Aaron
This's what I need.thank you.
ReplyDelete