My day today was somewhat peculiar. I’m quite fortunate in having the most stable Windows XP build in the office. Most of my colleagues tend to have problems with their laptops on a monthly basis. One can only guess at what they do to break their systems so often, but I blame it on incompetence…kidding.
So, where am I going with this? As you know, Sharepoint Services uses drag and drop DHTML for manipulating web parts on web part pages. This used to work find on my browser until yesterday. I spent hours trying to find a solution using Google and my own experimentation with IE. In the end out of desperation I logged on as a different user and found that IE worked fine with Sharepoint. So, must be something to do with the user profile. I deleted it and logged back on to have it recreated by the system, and hey presto, everything worked again. The really odd thing was that other web sites using a similar drag-n-drop DHTML script worked just fine all along.
What I really want to talk about today however is another Sharepoint related tidbit of information that might be useful to others. Namely, the RegisterWorkItemCallBack method available when writing webparts. This method allows a developer to perform some work asynchronously before RenderWebPart is called.
Now, Sharepoint is configured to impersonate the logged in user, so any web part code that runs is run as the impersonated user making the web request. You can verify this by using the following code in your RenderWebPart method:
output.Write( System.Security.Principal.WindowsIdentity.GetCurrent().Name);
This will show that the current WindowsIdentity is that of the currently logged-on user.
This is all well and good, and if you want to access any other resources as that authenticated user there is nothing stopping you (except for the double-hop issue, but that’s another story).
Where the problem lies, is when you want to access a resource as that user but from an asynchronous callback registered with the aforementioned RegisterWorkItemCallBack method. You see, this works in the same way as System.Threading.ThreadPool.QueueUserWorkItem but is designed to work with Sharepoints thread pool for reasons that escape me. The thread that executes a registered callback delegate DOES NOT run under the authenticated users context, but as the worker process identity that Sharepoint is configured to run under. This usually means NT AUTHORITY\NETWORK SERVICE.
Solution? The callback delegate is defined as accepting an object type parameter, so you can pass your callback any sort of state information that it might need. So just pass in a reference to the WindowsIdentity token of the current user. In your callback method, simply impersonate using that token, perform any resource access that you need, and revert back to the original thread identity. Check out the code below:
So, where am I going with this? As you know, Sharepoint Services uses drag and drop DHTML for manipulating web parts on web part pages. This used to work find on my browser until yesterday. I spent hours trying to find a solution using Google and my own experimentation with IE. In the end out of desperation I logged on as a different user and found that IE worked fine with Sharepoint. So, must be something to do with the user profile. I deleted it and logged back on to have it recreated by the system, and hey presto, everything worked again. The really odd thing was that other web sites using a similar drag-n-drop DHTML script worked just fine all along.
What I really want to talk about today however is another Sharepoint related tidbit of information that might be useful to others. Namely, the RegisterWorkItemCallBack method available when writing webparts. This method allows a developer to perform some work asynchronously before RenderWebPart is called.
Now, Sharepoint is configured to impersonate the logged in user, so any web part code that runs is run as the impersonated user making the web request. You can verify this by using the following code in your RenderWebPart method:
output.Write( System.Security.Principal.WindowsIdentity.GetCurrent().Name);
This will show that the current WindowsIdentity is that of the currently logged-on user.
This is all well and good, and if you want to access any other resources as that authenticated user there is nothing stopping you (except for the double-hop issue, but that’s another story).
Where the problem lies, is when you want to access a resource as that user but from an asynchronous callback registered with the aforementioned RegisterWorkItemCallBack method. You see, this works in the same way as System.Threading.ThreadPool.QueueUserWorkItem but is designed to work with Sharepoints thread pool for reasons that escape me. The thread that executes a registered callback delegate DOES NOT run under the authenticated users context, but as the worker process identity that Sharepoint is configured to run under. This usually means NT AUTHORITY\NETWORK SERVICE.
Solution? The callback delegate is defined as accepting an object type parameter, so you can pass your callback any sort of state information that it might need. So just pass in a reference to the WindowsIdentity token of the current user. In your callback method, simply impersonate using that token, perform any resource access that you need, and revert back to the original thread identity. Check out the code below:
IntPtr token = WindowsIdentity.GetCurrent().Token;
this.RegisterWorkItemCallBack( new WaitCallBack( MyHandler ), token );
…
private void MyHandler(object state){
IntPtr token = (IntPtr) state;
WindowsImpersonationContext ctx = WindowsIdentity.Impersonate(token);
// perform any resource access ( SQL Server/Web service/etc )
ctx.Undo(); //don’t forget to revert to original identity
}
Comments