Search Results Not Showing For Anonymous Users in A SharePoint Publishing Site

Whenever dealing with a public facing web site in SharePoint, my typical approach is to first set up the application using Windows authentication only, and then extend the application to an internet zone that would use the public URL, and allow anonymous authentication. Once I make the requisite site collection changes necessary for anonymous access, I actually go and remove NT Authentication from the Internet zone. This has benefits from both a security and testing standpoint.

This always worked like a charm in SharePoint 2007, but with SharePoint 2010, there’s a slight change in behaviour that affects search results. Typically, you will index the default zone URL, and when results are shown, they are translated into the correct zone’s URL. They are also security trimmed according to your credentials.

When I first started doing this with 2010 however, I observed that public (anonymous) users would get no search results whatsoever. A quick scan of the resources out there turn up a number of articles related to this behaviour such as this one, that indicate a change in the search visibility settings are in order. However, this didn’t seem to help my situation, and I suspect that that approach is pertinent to Team sites, not publishing sites.

A little more experimenting revealed the answer. As it turns out, it was my approach that was messing me up. It appears that anonymous visibility is now stored in the index as the content is indexed, instead of when the results are being rendered. Because the application that the indexer is reading from didn’t allow anonymous access, it assumed that the content wasn’t available to anonymous users generally.

The fix for this is simply to turn on anonymous access for your internal zone. This is actually a bit of a pain for internal users because they will not automatically be logged in to the site when they access it, but there are ways around that. Once anonymous access is enabled, all that you need to do is to run a full crawl on your content source, and you’re off to the races.

Hope this helps someone.

Using Silverlight and the SharePoint Client Object Model With Anonymous Access

One of the nicer features that SharePoint 2010 brought with it was the Client Object Model. Previously, all custom code had to either run on the server, using the SharePoint API. As an alternative, you could call the SharePoint SOAP web services from a client application, but in many cases, they left a little to be desired. The client object model brings the richness of the SharePoint API to client side development using either the full .NET framework, Silverlight, or jQuery.

Why is client side development important? Well, simply put, if you want to write an application or an add on for SharePoint, and you want it to run in both on-premise installations and in Office 365, it’s pretty much your only option, because you can’t deploy custom code to SharePoint Online. (OK, you can run sandboxed code in the cloud, but that brings its own set of severe limitations).

There are some great tutorials out there about working with the SharePoint Client Side Object Model (CSOM), so I’m not going to go into that here, but Tobias Zimmergren has an excellent getting started post – Getting Started With The Client Object Model. His example outlines using it with with the .NET CLR version, which is almost identical to Silverlight. As always, it’s the almost part that gets you. But more about that later.

There are a number of extra considerations when using the CSOM with an anonymous site. Since the code is executing on the client side, obviously the data needs to be accessible anonymously. Before we even touch the code, there are a number of things to check on the site itself.

1. Ensure that anonymous access is enabled

This may seem obvious, but it’s worth stating. Anonymous access needs to be enabled at both the web application level, and at the site collection level. One less that clear thing is that the option for enabling it at the site collection level does not even appear until it has been enabled at the application level. Randy Drisgill has an excellent post on how to do this here. As a best practice, I maintain one zone (usually the default) that uses Windows authentication, and my external zone, which allows ONLY anonymous access.

2. Turn off the ViewFormPagesLockDown feature

SharePoint publishing sites are designed to serve up pages, and to ONLY serve up pages to anonymous users. Standard SharePoint list items and forms cannot by default be accessed by anonymous users. This behaviour is controlled by the ViewFormPagesLockdown feature. This feature is enabled by default for publishing sites.

If the Silverlight application will be accessing any SharePoint list data, we will need to turn this feature off. Keep in mind that anonymous users will then have access to content stored in the site if they know how to access them, so you may want to use distinct anonymous access levels on some of your lists/libraries.

To turn off this feature, open a command prompt on your SharePoint server, and enter the following (replacing urlofsite with your url):

stsadm -o deactivatefeature -url http://urlofsite -name ViewFormPagesLockDown

Once you perform this step, you may need to re-set the anonymous access level for the site collection, as it doesn’t always pick up right away.

3. Allow GetItems() calls

For some bizarre (in my opinion…) reason, calls to the GetItems function is disabled by default for anonymous users. Waldek Mastykarz has a post about this issue, and what to do about it, which boils down to the following 3 lines of Powershell.

   1: $wa = Get-SPWebApplication -Identity "http://sharepoint" 

   2: $wa.ClientCallableSettings.AnonymousRestrictedTypes.Remove([Microsoft.SharePoint.SPList], "GetItems") 

   3: $wa.Update()

This will remove this restriction. Replacing “Remove” with “Add” will add it back.

4. Run the Application in Context

In order to work with the CSOM you will need to instantiate an SPContext object. This is the starting object for working with SharePoint objects. You can do this one of two ways. If you’re running the Silverlight application directly from a client (likely in development mode) or out of browser, you use its New constructor with the URL of the site as an argument.

_Context = New ClientContext(_URL)

 

If, However, you’re running from a SharePoint page, or a web part, you can use the current context.

_Context = ClientContext.Current

In Tobias’s tutorial mentioned above, he indicates that you can control the authentication mode through the AuthenticationMode property of the SPContext object. Possible values are Anonymous, Default, and Forms. As luck would have it, this property is not available to the Silverlight implementation of the SPContext object.

When working as an authenticated user, both options are available to you, but anonymous access only works with the second option. This makes debugging with anonymous sites difficult, as you need to either use a web part project, or copy your compile XAP file to the server manually. However, it’s only one line of code to change, so its entirely feasible to almost all of the development on the internal zone, and remember top change the mechanism before deploying to the anonymous zone.

5. Ensure That All of Your Resources Are Available.

If you’ve ever worked with an external site you’re familiar with the need to check in and approve all public facing content. It’s no different here. You need to ensure that all of the resources used by your application are available to anonymous users. I normally just try to load them all manually in a browser.

Once all of these steps are completed, you should be good to go with your anonymous site.

I wanted to add one other pointer here, although it has nothing to do with anonymous access. When you’re working with the CSOM, all of your calls are made asynchronously. This means that you make a request, and the result calls back into another method of your code. If you’re data binding, and showing results on screen, you will want to show the result as soon as it comes back. The problem is that many calls happen on a background thread, and when the try to access a data bound object, you’ll get the following error:

UnauthorizedAccessException: Invalid cross-thread access in Silverlight application

The trick is to force the update to happen on the UI thread. Steve Willcock at StackOverflow answered a similar question that includes a handy little helper object for forcing execution on the UI thread.

You don’t have to do client side development with SharePoint, but there are many advantages to doing so. The coming release of Office 365 makes it that much more compelling.