Export (0) Print
Expand All
Expand Minimize

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

SharePoint 2010

Summary:  Learn five tips related to claims-based authentication in SharePoint 2010, including resolving claims names, configuring for select zones, default solution deployment, and resolving error messages.

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.

I have heard a usage scenario question asked a few times that is related to claims providers: How do you configure a custom claims provider to be used only for a specific web application or a few web applications, instead of all of them? Originally, I was hoping that we could solve this scenario simply, and just scope the feature for the claims provider to the web application instead of to the farm. Well, that will not work.

A feature for a custom claims provider must always be scoped to the farm level. If you configure the scope of your feature to be anything different, you will get an error: "The method or operation is not implemented".

If the feature is scoped to the farm level, how do we configure the claims provider to be used only on selected web applications or zones? The answer is complicated. To begin with, it is important to understand two very important properties on a claims provider in the SPClaimProviderDefinition class: the IsEnabled property and the IsUsedByDefault property. By default, when you install a new claims provider feature, the claims provider has the IsEnabled and IsUsedByDefault properties set to true. This means that your claims provider is used everywhere that Security Assertion Markup Language (SAML) claims are enabled on a zone. Therefore, to even be able to configure a claims provider to be used only on selected zones, we first need to change the IsUsedByDefault property to false. As long as IsEnabled equals true and IsUsedByDefault equals false, we can configure the use of the claims provider on a per-zone basis.

Obviously, the next question is how do you set the IsUsedByDefault property to false? There are a couple of options here. One option is to use the feature receiver that you create for your custom claims provider and configure the property there. In the override for the FeatureActivated event (which you should already have coded anyway), you can use the SPClaimProviderManager to get a reference to your provider and set the IsUsedByDefault property to false. Following is an example that I used in one of my claims providers.

SPClaimProviderManager cpm = SPClaimProviderManager.Local;
 
foreach (SPClaimProviderDefinition cp in cpm.ClaimProviders)
{
if (cp.ClaimProviderType == typeof(SqlClaimsProvider.SqlClaims))
       {
       cp.IsUsedByDefault = false;
              cpm.Update();
              break;
       }
}

In this code, where typeof(SqlClaimsProvider.SqlClaims) is used, substitute the assembly and class name with your claims provider, for example, typeof(MyProvider.MyClaims). You can also wrap the code in a custom application. This is what I have done, and what I also use to demonstrate how the rest of this works throughout this article.

Figure 1 is a screen shot of my Claims Provider Activation application. On the left side of the application is a list of my registered custom claims providers (there is only one in this example). The check boxes below the registered custom claims providers are used to change the IsEnabled and IsUsedByDefault properties for the selected registered custom claims provider.

NoteNote

To download and try the Claims Provider Activation application, see Configuring a Custom Claims Provider to Be Used Only on Select Zones in SharePoint 2010.

Figure 1. Claims Provider Activation application displaying registered custom claims providers

Claims provider activation application

To set the properties, first select your custom claims provider, select the appropriate boxes to set the IsEnabled and IsUsedByDefault properties, and then click the Update button.

After your claims provider is configured to be IsEnabled but not IsUsedByDefault, you can configure where it is used. After your claims provider is configured this way, it is used only when the SPIisSettings for a zone contains the name of the claims provider in the ClaimsProviders property. Getting to this information is a little more difficult if you are trying to do it generically, as I did with the Claims Provider Activation application. The first step was to enumerate all of the web applications, which is done by using the SPService class.

//Get the content service.
SPWebService ws = SPWebService.ContentService;
 
//Get each web application.
foreach (SPWebApplication wa in ws.WebApplications)
{
//Enumerate each zone in each web application.
}

Enumerating each zone in a web application is a less common operation. Following is an example of how to enumerate each zone.

foreach (SPAlternateUrl aam in wa.AlternateUrls)
{
//Look at each zone to see whether it is using SAML claims.
}

To determine whether a zone is using SAML claims, I start by getting the SPIisSettings for the zone. As I mentioned earlier, to add or remove my claims provider from the ClaimsProviders property, I am going to need this anyway. The following code snippet shows how I get the SPIisSetting for the zone.

SPIisSettings curConfig = wa.GetIisSettingsWithFallback(aam.UrlZone);

In my curConfig variable, I can look at the ClaimsAuthenticationProviders property. If a zone is configured to use claims, then the ClaimsAuthenticationProviders property is not null, and the count is greater than zero.

I enumerate all the claims providers and, if I find the claims provider with the SPIisSettings for a zone contains the name of the claims provider in the ClaimsProviders property, I add the zone to my list of zones and show it as enabled. Otherwise, I cannot use my custom claims provider with that zone. So, I still add the zone to the list of zones, but show it as disabled.

That is the basics of how I generate the list of web applications and zones, and determine which zones can use a custom claims provider.

With that zone list, for any particular zone, my claims provider is used if the claims provider name is in the ClaimsProviders property of the SPIisSettings object.

The ClaimsProviders property is actually an IEnumerable of type string, so it is a little awkward to work with because it does not contain an overloaded method to Add or Remove or RemoveAt items. To get past that issue, I took the property and converted it to a List<string>, so that I could add or remove my claims provider name, and then I assign the List<string> back to the ClaimsProviders property.

Following is an example of the code.

List<string> providers = theZoneIisSettings.ClaimsProviders.ToList();
 
//NOTE: myClaimProvider is type SPClaimProviderDefinition.
if (EnableProvider)
providers.Add(myClaimProvider.ClaimProvider.Name);
else
       providers.Remove(myClaimProvider.ClaimProvider.Name);
 
//Plug the new values back into the ClaimsProviders Ienumerable.
theZoneIisSettings.ClaimsProviders = providers;
 
//You must get the web application that contains the zone, and then call its
//Update method to save your changes.
theWebApp.Update();

Figure 2 shows what the web application and zone selection looks like in the Claims Provider Activation application.

Figure 2. Claims Provider Activation showing web application and zones for a specific custom claims provider

Claims provider activation application and zones

In this case, the menu says Enable Basketball Teams because my Basketball Teams provider is not enabled for that zone. If it were enabled, the menu would say Disable Basketball Teams. Notice that in the zones above it, the SharePoint – Anon Profile Test web application is disabled. This is because those zones are not configured to use SAML claims.

That is how this all works. It is somewhat complicated, but also has lots of flexibility for configuration.

I have seen problems resolving claims names a few times now, so I want to try and share information about this issue, in case you are trying to troubleshoot. I have seen cases where you cannot get name resolution to work. For example, when you type in a name in the type-in control and then click the resolve button. You may even attach a debugger, if you have developed a custom claims provider, and you might see your claims provider do the right thing, but the name that you have typed still has a red squiggly line underneath, and search says that no matches are found.

What you will find about this particular problem is that the default claims providers no longer work either. For example, you can type NT Authority/All Authenticated Users, and it is not resolvable.

What is happening is that some claims provider, somewhere, is throwing an exception when its FillResolve overload is invoked. The particularly troubling thing here, as you may have guessed from the introduction of this tip, is that it means that one bad claims provider can bring down all name resolution in your farm.

So, if you find this scenario, where you cannot get the default claims providers to resolve names, start looking for custom claims providers. You probably need to remove them one-by-one to find the problematic claims provider, if you did not write all those custom claims providers. There are other concerns about removing them of course, primarily being that, if you add them back in a different order, they will not generate the same underlying claims that they did previously (because part of the claim is based on the order in which the claims provider was added).

But the main theme here is what to look for when you have this name resolution problem, and how to get rid of it.

Note Note

One thing that the previous information hopefully demonstrates is that custom claims provider developers should not be throwing exceptions in claims providers. If you do, you risk being the "bad" provider that can prevent name resolution from happening in a farm.

The three-logon-prompts problem when authenticating is all too common. I had this problem this weekend, but it was happening on my Active Directory Federation Services (ADFS) server, which I unfortunately was rebuilding. The most common reasons for the prompts have to do with some misconfigured Kerberos protocol setting, or with using some name other than the server name for a web application (the disable loopback scenario).

This problem is different though, and is specific to an ADFS server, so I wanted to capture it for future reference.

The Active Directory Federation Services (AD FS) 2.0 is actually good about writing problems to the event log. When you open the event viewer, you see a separate node for AD FS 2.0. That AD FS 2.0 node is the place to look for what the problem is. In this particular case, I did find the culprit there. It just took a fairly long time, because there are several different things that can give you the dreaded three logon prompts.

When I configured my ADFS server, I did the following:

  • Configured the ADFS server to run as a domain account

  • Used a certificate that I created just for ADFS for token signing

The problem was that the service account that I used for ADFS did not have rights to the private key for my token-signing certificate. That caused the three logon prompts, which is interesting, amazing, and frustrating all at the same time.

To grant rights to the service account to the private key for the certificate, you need to:

  1. Run the Microsoft Management Console (MMC).

  2. Add the Certificate MMC Snap-In (Certmgr.dll) for the Local Computer.

  3. Open the Personal node.

  4. Right-click the token signing certificate, and then select Manage Private Key.

I hope that this saves someone some time down the road.

One of my good friends, Tom W. (who authored the SharePoint 2010 Kerberos white paper), brought up a good point about limitations with solution deployment and the effect on custom claims providers. It is important to remember that when you develop a custom claims provider, it can be used in several places in addition to end-user web applications. For example, when you are creating web application policies in Central Administration, it is used there. When you are configuring user rights on My Sites, it is invoked there. If you are using the Secure Store Service, it is also called there.

The problem manifests itself as you build out bigger farms. Because those services are calling into the custom claims provider framework, the assembly of each custom claims provider needs to be placed in the global assembly cache on each of those servers. However, by default, the SharePoint solution deployment framework deploys solutions only to web front-end servers.

When you look at the schema for solution deployment, your only options for the DeploymentServerType attribute are the ApplicationServer value or the WebFrontEnd value. You really need both. That is because, in bigger farms, you may not be running the web application service on your application servers. If you are not, your custom claims providers are missing from the global assembly cache on those servers. If you try to use any of the features that call the custom claims provider framework, you generate errors because the assembly is missing.

Unfortunately, the following are the only current workarounds:

  1. Run the web application service on all servers in the farm.

  2. Write a custom deployment job, event receiver, timer job, or something similar, to get the assembly deployed to all the application servers.

  3. Deploy the assembly manually.

None of these options are particularly appealing. If I have to pick one, I would pick the first option (run the web application service on all servers in the farm) and just keep those servers out of the end-user load-balancing pool.

For now, I just wanted to raise the issue so that you are aware of it and can plan accordingly when you need to for your farm. Thanks again to Tom for pointing out this issue.

I have seen the TrustedMissingIdentityClaimSource error happen a few times to others and myself, so I wanted to share the likely culprit. The scenario is as follows: You set up claims-based authentication in SharePoint 2010. You are pretty sure that you have configured everything correctly.

However, when you actually try and navigate to the site, you may get the standard Microsoft ASP.NET error page that indicates a TrustedMissingIdentityClaimSource error (assuming that you have custom errors turned off). Most frequently, I have seen this error when email addresses are configured to be the identity claim, but the person that you are trying to log on with does not have an email address in Active Directory (or whatever directory you are using). It can be confusing because you see yourself getting redirected to ADFS (for the purposes of this discussion, it could also be any identity provider security token service). You see that you have been authenticated there, but then you get the TrustedMissingIdentityClaimSource error on Microsoft SharePoint Server.

This error serves as a reminder of the difference between who I am (the identity you log on with), and things about me (for example, attributes like email address and other claims that can be used for permissions provisioning in SharePoint 2010).

So, if you get this error, the first thing I recommend checking is whether the user account that you use to log on with has a identity claim value that the identity provider is expecting. Remember also that if there is no value in that attribute, the claim will typically not even be sent over to SharePoint Server (that is, for example, it will not be sent as an empty string value).

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 that are related to using and configuring claims, and points to other resources for more information.

Community Additions

ADD
Show:
© 2014 Microsoft