Tuesday, May 4, 2010

Anonymously accessing list items through the SharePoint Client Object Model

Up until today I haven't found time to explore the obscure corners of the SharePoint 2010 Client Object Model. Keeping an eye on my Twitter client, I noticed Waldek Mastykarz mention trying to use it in an anonymous portal context - and hitting an error doing so. Problems such as these easily catch my interest (that's my favorite way of learning new stuff), so I set out to try the same myself.

I whipped up an empty SP2010 team site, created a dummy list and added an item to that. I then went on to create a simple SilverLight package, such as:

public partial class MainPage : UserControl
{
private ListItemCollection _items;

public MainPage()
{
InitializeComponent();
var context = new ClientContext("http://sp10dev");
_items = context.Web.Lists.GetByTitle("TestList").GetItems(new CamlQuery { ViewXml = "100" });
context.Load(_items, items => items.Include(item => item["Title"]));
context.ExecuteQueryAsync(
(sender, args) => Dispatcher.BeginInvoke(ShowStuff),
(sender, args) => Dispatcher.BeginInvoke(() => MessageBox.Show("Request failed. " + args.Message + "\n" + args.StackTrace)));
}

private void ShowStuff()
{
foreach (var item in _items)
{
Output.Text += item["Title"] + "\n";
}
}
}

After adding this to the portal as a "Silverlight Web Part", using the default template, and enabling anonymous access to the portal, I got the following error:
Request failed. The method "GetItems" of the type "List" with id "{...}" is blocked by the administrator on the server.


This was quite unexpected, as I was able to retrieve information about the Web object, as well as enumerate lists (even a few hidden ones) in the portal.

Digging a bit further, I combined an exception I noticed in Fiddler (Microsoft.SharePoint.Client.ApiBlockedException), with the class information found in the client.svc endpoint. In Reflector, this brought me through the SharePoint 2010 client service code, to a class called SPClientServiceHost, which has a method named IsMethodBlocked. Following this trail even further, it turns out that there's a SPClientCallableSettings class, exposed as ClientCallableSettings on the SPWebApplication object - and that's the key. Turning to PowerShell for a second, I enumerated what turns out to be the default settings for the AnonymousRestrictedTypes property:


So apparently anonymous users, using the Client Object Model, are blocked from using
  • GetItems and GetChanges on SPLists
  • GetChanges and GetSubwebsForCurrentUser on SPWebs
  • GetChanges on SPSites

The good news, however, is that the ClientCallableSettings value can be adjusted to allow anonymous user access to one or more of these methods.

Doing this with PowerShell:

$webapp = Get-SPWebApplication "http://sp10dev"
$webapp.ClientCallableSettings.AnonymousRestrictedTypes.Remove([microsoft.sharepoint.splist], "GetItems")
$webapp.Update()

Be sure to replace "http://sp10dev" with whatever url your target webapp has. After doing this, anonymous calls to GetItems will work for that web application. The changes are persisted in the SharePoint database, and last until you change the setting again, or recreate the web application.

Update: I can't say for certain why GetItems() has been blocked by default, but this much I can say:
  • Per-item security is still upheld, with GetItems enabled. If anon doesn't have access to a list item, it won't be returned.
  • Even with GetItems disabled, the client side object model can be used by anonymous users to *add* items, granted that the list permits anon additions.

1 comment:

mdasblog said...

I'd be interested to know if there is analogous stuff in SharePoint 2007. I figured out a way to GetListItems (and other read methods) in v0.5.3 of SPServices, but it didn't feel right. http://mdasblog.wordpress.com/2010/03/18/allowing-anonymous-access-with-sharepoint-web-services-and-spservices/

M.