Monday 31 March 2008

Execute entire page with elevated privileges

I recently tried to make an entire page run under elevated privileges (just to see if I could). The idea was to override the IHttpHandler ProcessRequest method, elevate the privileges and then continue running the page.

This isn't something I would recommend doing. The idea came to me whilst trying to resolve a different issue with Form Digest during code executed under RunWithElevatedPrivileges. The solution to which can be found here Form Digest and SPSecurity.RunWithElevatedPrivileges.

However, I did manage to elevate the privileges of the entire page and this is how I did it.



The ProcessRequest method implements the IHttpHandler interface and is the entry point into the page. What I discovered is that both the SPContext class and the SPControl class both depend on objects initialised in the context.Items collection.
Elevating the privileges at this point means that the form digest control will be created in the context of the privileged account.

One issue that may arise is that client script sometimes updates the FormDigest value this could potentially invalidate the digest.

Leave a comment with your thoughts.

Form Digest and SPSecurity.RunWithElevatedPrivileges

A colleague of mine recently had an issue when running code using SPSecurity.RunWithElevatedPrivileges. The SPWeb's AllowUnsafeUpdates attribute had been set to true but an error was still occuring when calling methods that checked the FormDigest of the current page.

I found an article that said the answer to this is to disable the FormDigest settings on the web application using

SPSite.WebApplication.FormDigestSettings.Enabled = false

This means that when the form digest is validated it will always report that it is valid. My opinion on this though is that it isn't very safe. If you're creating a page that runs code under elevated privileges the last thing you want to do is introduce the ability to bypass form digest.

The Solution
That was when I discovered that the form digest is only validated once per request and then a flag is set in the page's context. Therefore, if you call the ValidateFormDigest method on the SPWeb object. This can easily be done using

SPUtility.ValidateFormDigest()

This will validate the form digest and cache the result ensuring that when the ValidateFormDigest is called within the SPSecurity.RunWithElevatedPrivileges wrapper it will always validate.

This solution means that FormDigest on the page will not be comprimised and the code will still run. You will still need to set AllowUnsafeUpdates to true.

Also for a bit of fun I decided to see if it was possible to run the entire page under elevated privileges. I'm not sure if you'd ever want to do this but this is what I came up with. Execute entire page with elevated privileges

Wednesday 19 March 2008

Open Containing Folder in Search Results

I was recently asked if it was possible to display a "Open containing folder" link in search results when the returned result was a document. My initial thought was that as seen as search results are created by applying a xsl stylesheet to some xml it shouldn't be a problem. I'll just modify the xsl in the search results web part...

Ah, right, ok then ...

I became stuck when I tried to determine the url of the containing folder. I originally intended to call some script embeded in the xsl that would work out the url but then I discovered that the xsl transformation in a DataViewWebPart, from which the search results web parts inherits, uses XSLTSettings.Default which disables scripting.

Then I got an idea. I would create a ficticious element, like the ie:menuitem elements sharepoint creates for the drop down menus, called ie:link with an attribute called url that I assign the results url to. This output is ignored by the browser but then at the end of my xsl stylesheet I render some javascript onto the page that returns all the ie:link elements and creates a link to the containing folder of the url (via a bit of string manipulation) and substitutes it back into the page.

To make this link only appear when rendering documents the output of the ie:link element is rendered inside a xsl:if element that checks the isdocument element.





Download sample xsl for search results web part.

Monday 10 March 2008

How to customise the SharePoint application.master file

Complete with source code.

So you want to customise your site. You create a master page; you even create your own theme. Just look at your perfect, beautiful site. Then you realise that every time you view a page in the layouts directory your master page is ignored.

This is because all these pages use the /_layouts/application.master master page. So how does one change this setting? In short the answer is you don't. Microsoft do describe two methods for cusomising application pages in the Layouts folder but both are lacking. Each method has advantages and over the other but neither satisfy my requirements.

I'd like to be able to
  • specify an alternate master page for any site (SPWeb) and have all sub-webs inherit the master page
  • configure the url to the master page via the UI
  • still use the uncustomised version of the application.master file


There are several components to the solution of this issue which can be download at the end of this post (including source code).

Changing the Master Page
In order to change the master page we need a way to check every page requested to see if we need to change the master page. To do this we will use a HttpModule. This will allow us to inspect the page being requested and if required attach an event to modify the master page.

The HttpModule will get the page handler and check the MasterPageFile property to see if it is set to the application.master. If it is, it will check the current web's property bag to see if an alternate master page has been specified. If no alternative is set, it will check the parent webs and inherit the setting. If an alternate is found an event handler will be attached to the page's init event that will then change the master page.

Configuring the Master Page
A custom action will be used to create a link in the Site Administration section of the site settings page. This will load a new application page that allows a site admin to set the alternate url for the master page that will be stored in the current web's property bag.

Sticking it all together
Nobody likes fixes that require manual changes to the file system and to the web.config files, so the aim is to create a single web application feature the can be installed, deployed and activated. The HttpModule requires modifications to the web.config file, this will be handled via a feature receiver that applies the web config modifications.

The feature will also install the application page that allows the site administrator to modify the URL to the alternate master page and add a link to the page into site settings under the Site Administration section.

To try this solution download the SharePoint solution file and install and deploy it on your farm. In Central Administration go to Manage Web Application Features and activate the Application Master Page feature on the required web application. After doing this if you go to the site settings page of any site on the web application you will see an Application Master Page link. Change the url to the location of your new master page.

Finally the Master Page
To test this solution you may wish to simply copy the application.master and make a small alteration so that you can see the difference. My recommendation for a full solution would be to create master pages using the application.master file as a template and deploy them to the layouts folder as part of your solution.

Download the solution here seed.hf2.wsp.

Download the source code here seed.hf2.zip

Please leave a comment if you found this post helpful or if you have any suggestions on how to improve it.