Radi Atanassov

SharePoint MCM, MVP, MCT and owner of OneBit Software

Fun with HTTP Handlers, Security Validations, FormDigest, AllowUnsafeUpdates, jQuery, AJAX and POST parameters in SharePoint

Ever seen this error message?

System.Exception: Microsoft.SharePoint.SPException: The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.

It is usually related to a missing SharePoint FormDigest control, or updates to the DB on an HTTP GET request. You might hear people saying you should set AllowUnsafeUpdates to true, but in the case of a POST request that is not the best thing you could do. The best resource that you could ever read on the topic is written a while back (in 2008!) by a good friend of mine and ex colleague - Hristo Pavlov. These two posts are your best starting point if you want to understand what these items are for and how they achieve their purpose.

What You Need To Know About AllowUnsafeUpdates (Part 1)

What You Need To Know About AllowUnsafeUpdates (Part 2)

Generally speaking, AllowUnsafeUpdates = true on POST shouldn’t be required at all. I was working with my team on an HTTP Handler living in the SharePoint Layouts folder and it was failing with the security validation exception. In a typical ASPX web page you would include the SharePoint FormDigest control and SharePoint will handle it from there onwards:

<SharePoint:FormDigest runat="server"/>

 

You will notice the output of this control is a hidden <input> like this one:

 

<input name="__REQUESTDIGEST" id="__REQUESTDIGEST" type="hidden" value="0xDA527A96…A23,22 Apr 2011 14:17:06 -0000"/>

 

SharePoint will use this control (in particular the parameter __REQUESTDIGEST) and validate the “FormDigest”. You can explicitly call the SPUtility.ValidateFormDigest() helper method achieves the same. (See Hristo’s blog posts for more info on how it works). It basically takes the __REQUESTDIGEST value and validates it on the request object.

 

But in an HTTP Handler you don’t have the <SharePoint:FormDigest /> control as there is no ASPX. Developers can get the handler working by setting AllowUnsafeUpdates on the SPWeb object, but this should be avoided when it could (see Hristo’s post on why it is not good). If you are making a POST request, pass in the __REQUESTDIGEST and make sure you call the SPUtility.ValidateFormDigest() method before you do any DB updates.

 

If you want to call your handler asynchronously with AJAX, lets say with jQuery, this adds another level of complexity. You have to pass in the __REQUESTDIGEST parameter for SPUtility.ValidateFormDigest() to succeed. I personally found documentation on the $.ajax jQuery method quite poor, but here is a JavaScript example on how to use it and pass the __REQUESTDIGEST <input/> value:

function UploadFileAsync() {

    var listId = $("input[id$='hdnListID']").val();

 

    $.ajax({

        type: "POST",

        url: "/_layouts/Handlers/FileUpload.ashx?ListID=" + listId,

        contentType: "application/x-www-form-urlencoded",

        data: "__REQUESTDIGEST=" + $("#__REQUESTDIGEST").val(),

        timeout: 30000,

        success: function (response) {

            alert(response);

        },

        error: function (x, t, m) {

            if (t === "timeout") {

                alert("got timeout");

            }

            else {

                alert(t);

            }

        }

    });

}

A few things are important and worth mentioning. In the “data” parameter I get the value of __REQUESTDIGEST and pass it in the POST request. (NOTE: you may want to improve the $(“#__RE..”) selector to get only input/hidden elements and be better performing). This will allow SPUtility.ValidateFormDigest() to pass successfully. If ever in doubt, open the request with Fiddler and validate the contents, you should see something like this:

clip_image001

The other important point is the contentType parameter. For me this did not work when set to “text/plain; charset=utf8”. I didn’t have enough time to figure out why, but “application/x-www-form-urlencoded” succeeded successfully.

Hope this helps!

Silverlight install errors and changing the default Program Files location (NOT SharePoint)

I was having problems installing both Flash and Silverlight on a new build, and thought I might share my situation.

I have an SSD drive (C:\)and another 7200 RPM mechanical HDD (D:\). I did quite a bit reading on how to optimize my SSD’s lifetime, and many sources say that we shouldn’t worry about taking much care of our SSD’s. They live longer now + mine has a 3 year warranty. I still wanted to implement some tweaks, and I also wanted to place some rarely used program files on my mechanical drive. Things I did: Move page file to D: (and reduce it as I have 16GB RAM), put browser and Windows temp files on D:, set download folder to D:, and some others which I don’t recall anymore (: Many might ask why, but that is for another discussion.

The challenge I was having is setting Program Files to default on D:. I did not do this during the installation of Windows 7, and I couldn’t find a “supported” way change from C: to D:, so I went ahead and changed the registry key, expecting something to fail at one point in time. Everything seems fine and it has been 2 months and I have passed many installations, but the first things that failed we’re Flash and Silverlight. Both addons gave meaningless error messages.

Reg Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir AND \ProgramFilesDir (x86)

The fix is easy, change the registry key back to C:, restart, install them and return it to D: I want it to stay D: so it is the default when installing applications. Note, I actually had to restart, but you could probably get away with log off/log on.

So to close this off, changing the default program files directory is not supported, it may be fine at first, but you might get nasty errors later on. Plan this during the installation of Windows 7, rather than forget like me.

And just as a side note, I’ve always been a fan of hacking and customizing my OS… I have done various other things to it, some I understand, but some that I don’t and shouldn’t do. I installed some Lenovo software/drivers, then decided to modify my start button and chrome, and now Windows 7 thinks it’s not genuine and it keeps reminding me! I can live with that (I probably have 3 Windows 7 licenses and 1 laptop), but it should stick as a warning to everyone (:

SharePoint 2010 Search: Some Managed Properties cannot be included in queries

A colleague today showed me a problem he was having with full text search queries. All he was doing is including the ContentType managed property in the search query, which returned a Microsoft.Office.Server.Search.Query.InvalidPropertyException.

The reason for this is that the Content Type field is now marked as non-retrievable. The ManagedProperty class has a “Retrievable” property, which according to this MSDN article, specifies whether it can be used in queries: microsoft.office.server.search.administration.managedproperty.retrievable.aspx

According to this blog post, it used to be retrievable in SharePoint 2007. Definitely a gotcha - most people would think this is possible, and most may also sell it in a client meeting.

The problem is that you cant set it to true… I currently have no solution for this, but I thought I might post a list of ALL managed properties (in a default installation with very few content) that have Retrievable set as False.

PowerShell script to check properties:

Get-SPEnterpriseSearchMetadataManagedProperty -SearchApplication "Search Service Application" | where {$_.Retrievable -eq $false}

Results:

Account
BestBetKeywords
CategoryNavigationUrl
Colleagues
ContentsHidden
ContentSource
ContentType
DocComments
DocKeywords
DocSignature
DocSubject
EndDate
ExcludeFromSummary
ExpirationTime
FollowAllAnchor
HostingPartition
ModifiedBy
NLCodePage
Notes
OWS_URL
PrivateColleagues
Purpose
RankingWeightHigh
RankingWeightLow
RankingWeightName
SiteID
SocialTagTextUrl
SPSiteURL
StartDate
UrlDepth
WikiCategory

OK so I looked into it further, I tried setting it in the Search SA to be included in all results, but that didn’t work:

image

clip_image001

And adding it in the advanced search web part also doesn’t work:

clip_image001[6]

The query will return no results. Trying to set the property to True in PowerShell or the OM still gives the same error.

So, the only workable solution that is flying around is the one posted on the MSDN forums. It still, however, is a workaround that can’t be used in ALL situations out there. This is not great, as one would think the ContentType field is something you would want to include in your search results.

Please let me know if you find any other solutions.

Troubleshooting Permissions with Excel Services

I was setting up Excel Services with Kerberos following the steps of this great whitepaper:

Configuring Kerberos authentication for SharePoint 2010 Products

I did everything fine, except I missed a step a while back when initially configuring the farm with least privileged accounts. This led to an interesting permission troubleshooting exercise, so I thought it might be interesting to share.

It started of with a frequent error when opening an Excel document with a connection to a database on an SQL server. The error: The workbook cannot be opened.

clip_image001

Great.

First place to look: the grand ULS logs:

clip_image002

The error was obvious, the Excel Service Application service account didn't have access to the Content Database of the web application. But hang on, I was confident I allowed it access via the PowerShell script described in the document:

$webApp = Get-SPWebApplication -Identity https://claims.mcm.com

$webApp.GrantAccessToProcessIdentity("mcm\svc_excel")

So I did it again:

clip_image003

Naturally, the next step would be to check the DB's, and to my surprise there was no "SharePoint_Shell_Access" assigned to the svc_excel user. In fact there was nothing in there for him...

PowerShell didn't indicate any errors, but ULS clearly did:

clip_image004

The user running the PowerShell script (mcm\sharepointowner), which is also the SP Farm Account, didn't have access to the DB. But more specific, I must have forgot to give that user PowerShell access in this particular SharePoint farm. I'm sure I did it, but it must have been on another farm (my lab is running 3 farms).

Most of you will have guessed the solution by now - run the PS Add-SPShellAccess command as I should have during the install of the farm:

Add-SPShellAdmin -Username "mcm\sharepointowner" -Database (Get-SPContentDatabase -Identity "WSS_Content_ClaimsDB")

Here's a PS screenshot:

clip_image005

Running the GrantAccessToProcessIdentity() goes ahead again, but this time the ULS logs appropriately show success:

clip_image006

It is worthwhile to point out how the command adds "mcm\sharepointowner" to WSS_ADMIN_WPG and gives "SharePoint_Shell_Access" to both the Config and Admin Content DB's on top of the Content DB.

Hope this helps!

SQL Disk Space Errors in SBS 2003 R2

I was working on a VM and stumbled upon a TEMPDB issue. I was getting disk is full errors…:

C:\Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\DATA\tempdb.mdf: Operating system error 112(There is not enough space on the disk.) encountered.

Could not allocate space for object '<temporary system object: >' in database 'tempdb' because the 'PRIMARY' filegroup is full.

This may occur for other databases as well, or for that matter, other files.

I had a look around and had appropriate disk space, so I new that wasn't the issue. SQL services we're running under a service account, so I started looking around to make sure the service account has enough rights to use large amounts of space. I couldn't expand the TEMPDB size manually in SQL Server Management Studio and Quota's in AD/Group Policy we're not configured, so that wasn't the problem.

If you right-click on the drive where TEMPDB is located, you will see that SBS has quota enabled by default (in my case it was the C: drive and that would have the setting ON by default).

Here's the Quota tab where you could disable it:

clip_image001

Turning quota management off will allow the service account to use up disk space and enlarge its TEMPDB. This should be only turned off on a development environment or if you really know what you are doing. It is also best practice to relocate the TEMPDB on a different disk for performance reasons.

Hope this helps!