Claims Tips 3: Learning About Claims-Based Authentication in SharePoint 2010

Summary:  Learn five tips that are related to claims-based authentication in SharePoint 2010, including information about packaging, retrieving REST data, adding policy, managing trusted root authorities, and resolving logon page issues.

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

  • Overview of the Scope of This Article

  • Tip 1: Packaging a SharePoint 2010 Custom Claims Provider in a Visual Studio 2010 SharePoint Project

  • Tip 2: Retrieving REST Data in a Claims-Based Authentication Site in SharePoint 2010

  • Tip 3: Adding a Custom Claim to a Web Application Policy by Using Windows PowerShell in SharePoint 2010

  • Tip 4: Managing Trusted Root Authorities for Claims-Based Authentication in SharePoint 2010 Central Administration

  • Tip 5: Resolving AD FS Authentication Page Logon Issues in SharePoint 2010

  • Conclusion

  • Additional Resources

Overview of the Scope of This Article

This article provides tips for and answers to frequently asked questions related to claims-based authentication in Microsoft SharePoint 2010. It also provides tips and guidance to help solve problems related to using and configuring claims, and points to other resources for more information.

Tip 1: Packaging a SharePoint 2010 Custom Claims Provider in a Visual Studio 2010 SharePoint Project

If you have been developing solutions for SharePoint 2010 by using Microsoft Visual Studio 2010, you may have noticed a slight packaging peculiarity when it comes to custom claims providers. In Visual Studio 2010, you can create a new feature and then easily add a feature event receiver to the new feature by right-clicking on the feature and selecting the Add Event Receiver menu. This is nice because it increases productivity and makes it easier to work on the code for your solution, rather than spending time on the configuration.

However, a disconnect comes in because the event receiver that Visual Studio 2010 adds by default is inherited from SPFeatureReceiver. As you may know, the event receiver that is used to register a custom claims provider must inherit from SPClaimProviderFeatureReceiver (see Claims Walkthrough: Writing Claims Providers for SharePoint 2010). In addition, the built-in SharePoint smarts in Visual Studio do not provide a really intuitive way to just add a class to a SharePoint 2010 project and then have it be associated with a feature.

There is, however, a fairly easy and slick way around this. I went down this path a while ago when I was beginning with my usual starting point—I had a custom claims provider that I had written and a corresponding feature receiver to install it. These two classes were part of a single project. I decided that I really wanted to make the new packaging feature in Visual Studio 2010 work for me, so here is how I did it:

  1. Complete your first coding run of your custom claims provider project and corresponding event receiver for registration, and then compile it. Look at the compiled assembly to get the strong name for the assembly and the class name for the event receiver.

  2. Add a new project to your solution. Base the new project on a Empty SharePoint Project template for SharePoint 2010. Configure the project to be deployed as a farm solution.

  3. Right-click the Features node in the project, and then select Add Feature. Your feature should be scoped to Farm and should auto-activate. Otherwise, configure the feature properties as appropriate for what you are trying to do. Here is the important point—configure the following two properties on the feature (in the Visual Studio Properties window) as described:

    • Receiver Assembly   Type the strong name to your assembly that is described in step 1.

      For example, type the following: MyClaimProvider.ClaimTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=edb00fee02fa0701

    • Receiver Class   Type the name of the event receiver class that you wrote for your custom claims provider in step 1.

      For example, type the following: MyClaimProvider.ClaimTest.MyClaimsFeatureReceiver

  4. Add your compiled custom claims provider assembly to the list of assemblies that your packaging solution is deploying, as follows:

    1. Double-click the Package.package node in the Visual Studio packaging project.

    2. On the Advanced tab, click Add, and then click Add Existing Assembly.

    3. Find the correct location for your compiled custom claims provider assembly, and leave the default Deployment Target: GlobalAssemblyCache selected.

    4. Click OK to save your changes, and then close the Package properties window.

One thing to notice here for step 4: I usually just create a folder in my packaging project where I copy my compiled assemblies from other projects that I want to be distributed with the solution. When I configure the additional assemblies in the Package window, I just select the assemblies from the folder in my packaging project. In my other projects, I have a post-build script that automatically copies the compiled assembly into this assembly folder in my packaging project. It is a simple single line of code post-build that copies the assembly (whether it is a debug build or a release build) so that I do not need to remember to do it myself each time. Following is the code (assuming that you create a folder named GacFiles to store these assemblies).

copy "$(TargetPath)" ..\..\..\MyPackagingProject\GacFiles /Y

Your package is now complete. You just need to compile the package project and then, on the shortcut (right-click) menu for the project, select Package. You then have a solution package (.wsp file) that you can distribute, and you can have the solution package automatically roll out your custom claims provider.

Tip 2: Retrieving REST Data in a Claims-Based Authentication Site in SharePoint 2010

Note

This tip is a small part of one section of a white paper about claims and SharePoint 2010 that is being published.

SharePoint 2010 provides the ability to retrieve list data through a Representational State Transfer (REST) interface. In this example, I reuse the code that gets the FedAuth cookie that was included with the Using the Client Object Model with a Claims-Based Authentication Site in SharePoint 2010 blog post. After I have the FedAuth cookie, I reuse it to make a call to retrieve list data through REST.

The call is slightly different because we need to do HTTP GETs directly against the list data service in SharePoint 2010. The list data service is available in any site by navigating to the _vti_bin directory. For example, if you have a site at https://contoso, to get all of the items in the Contacts list on that site you could make a request to https://contoso/_vti_bin/listdata.svc/Contacts. The data is returned as XML, which you can then process as needed for your application.

The following is a code example that reuses the method to obtain a FedAuth ticket, and then retrieves a list of all the items in the Contacts list.

private void GetRestDataBtn_Click(object sender, EventArgs e)
{
try
{
//This is the REST endpoint that I want to use to get all Contacts.
string endpoint = "https://fc1/_vti_bin/listdata.svc/Contacts";
//Get the FedAuth cookie.
string FedAuth = GetSamlToken();
//Make a request to the REST interface for the data.
HttpWebRequest webRqst = (HttpWebRequest)WebRequest.Create(endpoint);
webRqst.UseDefaultCredentials = true;
webRqst.Method = "GET";
webRqst.Accept = "*/*";
webRqst.KeepAlive = true;
//Create the FedAuth cookie that goes with our request.
CookieContainer cc = new CookieContainer();
Cookie samlAuth = new Cookie("FedAuth", FedAuth);
samlAuth.Expires = DateTime.Now.AddHours(1);
samlAuth.Path = "/";
samlAuth.Secure = true;
samlAuth.HttpOnly = true;
Uri samlUri = new Uri(SamlTxt.Text);
samlAuth.Domain = samlUri.Host;
cc.Add(samlAuth);

//Plug our cookie into the request.
webRqst.CookieContainer = cc;
//Read the response now.
HttpWebResponse webResp = webRqst.GetResponse() as HttpWebResponse;
//Make the request and get the response.
StreamReader theData = new StreamReader(webResp.GetResponseStream(), true);
string payload = theData.ReadToEnd();
theData.Close();
webResp.Close();

//Create the XML classes for working with the results.
XmlDocument xDoc = new XmlDocument();
//XML doc, loaded with the results.
xDoc.LoadXml(payload);
//Namespace manager, used for querying.
XmlNamespaceManager ns = new XmlNamespaceManager(xDoc.NameTable);
ns.AddNamespace("b",
"http://www.w3.org/2005/Atom");
ns.AddNamespace("m",
"https://schemas.microsoft.com/ado/2007/08/dataservices/metadata");
ns.AddNamespace("d",
"https://schemas.microsoft.com/ado/2007/08/dataservices");
//Query for items.
XmlNodeList nl = xDoc.SelectNodes("/b:feed/b:entry/b:content/m:properties", ns);
//Create a list to hold the results.
List<Contact> Contacts = new List<Contact>();
//Enumerate the results.
foreach (XmlNode xNode in nl)
{
Contacts.Add(new Contact(
xNode.SelectSingleNode("d:FirstName", ns).InnerText,
xNode.SelectSingleNode("d:LastName", ns).InnerText,
xNode.SelectSingleNode("d:Company", ns).InnerText,
xNode.SelectSingleNode("d:JobTitle", ns).InnerText,
xNode.SelectSingleNode("d:EMailAddress", ns).InnerText));
}
//Bind to the DataGridView on my form.
ContactGrd.DataSource = Contacts;
}
catch (Exception ex)
{
//Add your error code handling here.
}
}
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Company { get; set; }
public string JobTitle { get; set; }
public string Email { get; set; }
public Contact(string First, string Last, string Company, string Title, string Email)
{
this.FirstName = First;
this.LastName = Last;
this.Company = Company;
this.JobTitle = Title;
this.Email = Email;
}
}

Stepping through the code, you can see that it first gets the FedAuth cookie from SharePoint 2010, as demonstrated in the blog post that I linked to earlier: Using the Client Object Model with a Claims-Based Authentication Site in SharePoint 2010. After the cookie is obtained, a new HttpWebRequest is made that is used to call the REST interface in SharePoint to retrieve all items in the Contacts list. A new cookie is created where the FedAuth cookie that was retrieved can be placed; this is what enables SharePoint to view our request as being authenticated. After the cookie is added, the request is made to the REST interface in SharePoint to retrieve the data. The results are put into the string variable payload.

Tip 3: Adding a Custom Claim to a Web Application Policy by Using Windows PowerShell in SharePoint 2010

I found this process to be much more difficult than anticipated, and then much easier than expected once done, so I figured I would do a quick tip about it. The task is to add a custom claim to a web application policy by using Windows PowerShell.

Adding a custom claim to a web application is straightforward by using the SharePoint Central Administration user interface. However, using Windows PowerShell is a different story, especially when you have never done it before. I was initially taking the approach of creating a New-SPClaimsPrincipal to add to the policies for the zone. Just for your amusement, the following is a variety of different approaches that I tried (and far from all of the different permutations I looked at).

#$tp = Get-SPTrustedIdentityTokenIssuer -Identity "ADFS with Roles"
#$cp = Get-SPClaimProvider -Identity "BasketballTeamProvider"

#$account = New-SPClaimsPrincipal -ClaimValue "Wingtip Toys" -ClaimType "Role" -TrustedIdentityTokenIssuer $tp
#$account = New-SPClaimsPrincipal -Identity "Wingtip Toys" -TrustedIdentityTokenIssuer $tp
#$account = New-SPClaimsPrincipal -Identity "c:0ǹ.c|basketballteamprovider|wingtip toys" -IdentityType EncodedClaim
#$account = New-SPClaimsPrincipal -ClaimValue "Wingtip Toys" -ClaimType "http://schema.steve.local/teams" -ClaimProvider $cp.ClaimProvider
#$account = New-SPClaimsPrincipal -EncodedClaim "c:0ǹ.c|basketballteamprovider| wingtip toys "

Many of these approaches added the claim successfully, but it was clearly not the correct identifier because the policy was not implemented (that is, I granted Full Control, but users with that claim could not log on). This was the "more difficult than anticipated" phase.

To get it to work, I really did not need a New-SPClaimsPrincipal object at all. Instead, the following Windows PowerShell code got the claim correctly added and working.

$WebAppName = "https://contoso1"
$wa = get-SPWebApplication $WebAppName
$account = "c:0ǹ.c|basketballteamprovider|wingtip toys "

$zp = $wa.ZonePolicies("Default")
$p = $zp.Add($account,"Claims Role")
$fc=$wa.PolicyRoles.GetSpecialRole("FullControl")
$p.PolicyRoleBindings.Add($fc)
$wa.Update()

So, just adding the custom claim as a simple string is what worked. Notice that to get the $account value, I just added the policy by using Central Administration, and then copied the claim value that it displayed when done. I then use the claim value that I copied from the user interface in my code. Hopefully, this will save you some time should you need to do this in the future.

Tip 4: Managing Trusted Root Authorities for Claims-Based Authentication in SharePoint 2010 Central Administration

I thought I would create this tip to raise awareness about another way to manage trusted root authorities in SharePoint 2010. For those of you who have been doing claims authentication sites, you know that you need to add all the certificates in the token-signing certificate chain to the SharePoint list that contains SharePoint trusted sites. All of the previous examples that I have demonstrated in my blog posts have done that through Windows PowerShell. To give equal coverage, I thought I would just let you all know that you can do the same thing in Central Administration.

You can add, change, or delete a trusted root authority for your token-signing certificate chain by using Central Administration. To do so, go to SharePoint 2010 Central Administration, click Security, and then click Manage trust. This takes you to the Trust relationship page. On this page, you can see the trusted root authorities that have been defined. You can add or edit trusts by browsing for a certificate that SharePoint uploads and uses to establish a trust. Just ensure that you do not delete the local trusted certificate, which is for the internal SharePoint security token service (STS).

Tip 5: Resolving AD FS Authentication Page Logon Issues in SharePoint 2010

I have had trouble resolving Active Directory Federation Service (AD FS) Authentication page logon issues several times, so I thought I would describe this problem and resolution because I am sure that others have seen it too.

Let's assume that you have configured a SharePoint web application to use SAML claims, and the identity provider security token service (IP-STS) is Active Directory Federation Services (AD FS) 2.0. Sometimes I see that after SharePoint redirects to the AD FS login page, the browser just "stops". The status says "complete", as if the page is completely loaded and the blank page is all there is to it. The address bar in the browser shows the correct AD FS server URL. No error is shown and the browser looks like it is at the AD FS logon page. But, you are never authenticated, never prompted for credentials, and never sent back to your SharePoint site.

When this happens, I have found the problem is that I have a proxy server configured in my browser, and the request is being redirected to the fully qualified domain name of the AD FS server (that is, https://adfs.contoso.com).

To fix the problem, in Internet Explorer, do the following:

  1. On the Tools menu, click Internet options.

  2. On the Connections tab, click LAN settings.

  3. Click Advanced to open the Proxy Setting window.

In the Proxy Setting window there is a text box for exceptions. The Exceptions text box is where you add URLs that you do not want the proxy server to try to resolve for you. If you add the URL for your AD FS server to that list and then save your changes, you should be able to successfully redirect and get authenticated.

Unfortunately, there is no feedback from the browser in this scenario as to what is the problem. If you get the "blank screen" browser page, consider this tip as a possible fix.

Conclusion

This article provides answers to some frequently asked questions about claims-based authentication in SharePoint 2010. It also provides five tips and guidance to help solve problems related to using and configuring claims, and points to other resources for more information.

Additional Resources

For more information, see the following resources: