Retrieving Data from a Multi-Authentication Site Using the Client Object Model and Web Services in SharePoint 2010

Summary:  Learn how to retrieve data from a multi-authentication site by using the client object model and web services in SharePoint 2010.

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Provided by:  Steve Peschka, Microsoft Corporation

Contents

  • Retrieving Data from a Multi-Authentication Site by Using the Client Object Model and Web Services in SharePoint 2010

  • Conclusion

  • Additional Resources

Retrieving Data from a Multi-Authentication Site by Using the Client Object Model and Web Services in SharePoint 2010

In this article, I am covering only the most common parts of how to retrieve data from a multi-authentication site by using the client object model and web services; there are multiple twists that can be added. The scenario is to retrieve data from a SharePoint site that is using multiple authentication providers. In this scenario, assume that one of the authentication providers is Windows claims and the other authentication provider is anything else—it could be forms-based authentication or a SAML authentication provider. Often you want to retrieve data from such a site by using either the client object model or SharePoint web services, but you want to use Windows authentication to do so. The problem up to this point has always been that even when you set your Windows credentials on the request, you still get an access denied error when requesting the data.

The resolution to this problem is that, if you want to programmatically access a SharePoint site that uses multiple authentication providers by using a set of Windows credentials, you must add an additional header to your request. The header name must be X-FORMS_BASED_AUTH_ACCEPTED and the value must be f. Adding this header can be a bit complicated for these two common scenarios (that is, using the client object model or web services). The rest of this article explains how to do that and gives some sample code. If you are using the client object model, you must add an event handler for the ExecutingWebRequest event. The following is a code example.

//Create the client context.
ClientContext ctx = new ClientContext(MixedUrlTxt.Text);
//Configure the handler that will add the header.
ctx.ExecutingWebRequest +=
new EventHandler<WebRequestEventArgs>(ctx_MixedAuthRequest);
//Set the Windows credentials.
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials = System.Net.CredentialCache.DefaultCredentials;
//Get the web.
Web w = ctx.Web;
//Load lists with all properties. 
var lists = ctx.LoadQuery(w.Lists);
//Execute the query.
ctx.ExecuteQuery();
//Enumerate the results.
foreach (List theList in lists)
{
//Do something with each list.
}

The following code example is where the magic happens.

void ctx_MixedAuthRequest(object sender, WebRequestEventArgs e)
{
try
{
//Add the header that tells SharePoint to use Windows authentication.
e.WebRequestExecutor.RequestHeaders.Add(
"X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
catch (Exception ex)
{
MessageBox.Show("Error setting authentication header: " + ex.Message);
}
}

That is all there is to it; the code is actually straightforward and self-explanatory. Doing the same thing by using a standard web service reference is a little different. To begin with, let us walk through the process of adding a standard web reference in a SharePoint site to a project in Microsoft Visual Studio 2010:

  1. In Microsoft Visual Studio 2010, on the Project menu, click Add Service Reference.

  2. In the Add Service Reference dialog box, click Advanced.

  3. Click Add Web Reference.

  4. In the URL box of the Add Web Reference dialog box, type the URL to the web service that you want to use; for example, to add a reference to the Lists web service, type http://site/_vti_bin/lists.asmx.

  5. In the Web reference name text box, rename your web service reference to a name of your choosing.

  6. Click Add Reference, to add a web reference for the target web service.

Your reference and proxy classes for your reference are created now, but you have to add another partial class to add the header to your web service request. Start by adding a new class to your project, name it whatever you want. Because you just want to add some additional behavior—adding a header to the request—make it a partial class. To make it a partial class, you must copy both the namespace and the class name that is used in the proxy created for your web reference:

  1. In Solution Explorer, click Show All Files.

  2. Under Web Reference, expand your web service reference.

  3. Expand Reference.map, and then double click Reference.cs to open the file.

  4. Copy the namespace into your class.

  5. Copy the class name, including inheritance, into your class as your class name. The web service reference class is a partial class already, so you do not need to make any changes.

The following is an example of what my Reference.cs class looks like for my web service reference.

namespace ClientOmAuth.listsWS {
using System;
using System.Web.Services;
using System.Diagnostics;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Xml.Serialization;
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="ListsSoap", Namespace="https://schemas.microsoft.com/sharepoint/soap/")]
public partial class Lists : System.Web.Services.Protocols.SoapHttpClientProtocol {

The following is what I copied into the class that I created.

public partial class Lists : System.Web.Services.Protocols.SoapHttpClientProtocol
{
}
}

Notice how both the namespace and the class names match, and notice that both classes are inheriting from the same base type. Now you have to override the GetWebRequest method so that you can add the header. You do this simply by adding the following code to your partial class.

protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.WebRequest wr = null;
try
{
wr = base.GetWebRequest(uri);
wr.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
catch (Exception ex)
{
//Some error handling goes here.
}

return wr;
}

Writing the code to retrieve the data via the web service is now identical to the code that you would write for any SharePoint site that is using Windows authentication.

//Create the web service proxy and configure it to use my Windows credentials.
listsWS.Lists lws = new listsWS.Lists();
lws.UseDefaultCredentials = true;
//Get the collection of lists.
XmlNode xLists = lws.GetListCollection();
//Enumerate the results.
foreach (XmlNode xList in xLists.ChildNodes)
{
//Do something with each list.
}

That is all there is to it. You can apply this information to retrieve data via Representational State Transfer (REST) also, by using the techniques that I described in Claims Tips 3: Learning About Claims-Based Authentication in SharePoint 2010, in the section Tip 2: Retrieving REST Data in a Claims-Based Authentication Site in SharePoint 2010.

Conclusion

This article describes how to retrieve data from a multi-authentication site by using the client object model and web services in SharePoint 2010.

Additional Resources

For more information, see the following resources: