«

Jan
29
2012

Custom claim providers for SharePoint – lessons learned

In a number of the websites we have running on SharePoint 2010 we use custom claim providers. In this post I will describe the issues/challenges we had when creating and registering these providers.

Availability

The way to register a custom claim provider is to create a feature the does the job. You do this by creating a feature receiver and inheriting your receiver from SPClaimProviderFeatureReceiver as described by Steve Peschka. This needs to be a farm scoped feature. After activation, your custom claim provider is available in every web application, on every zone. This means that after a user logs in on one of your web sites, SharePoint notifies all registered claim providers and asks for claims for the user that is logging in. This applies to both an internal user on the internal (default) zone, or a internet user logging in to your website. In our farm we have websites for multiple labels, which means that the custom claim provider for website X of label A also kicks in for website Y, belonging to label B. In a later blogpost, Steve also decribes how to solve that. In the feature receiver, you need to set the IsUsedByDefault property of the SPClaimProviderDefinition to false:

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

    ExecuteBaseFeatureActivated(properties);

    SPClaimProviderManager cpm = SPClaimProviderManager.Local;

    foreach (SPClaimProviderDefinition cp in cpm.ClaimProviders)

    {

        if (cp.ClaimProviderType == typeof(YourCustomClaimProvider))

        {

            cp.IsUsedByDefault = false;

            cpm.Update();

            break;

        }

    }

}

We can now control exactly on what web application, on what zones our providers kick in.

LESSON 1: Before choosing the easy way out and making your claim providers available throughout the whole farm, think about if this is really what you want. Apart from the performance penalty you will get, you will probably find lots of errors in your log files that were generated by your claim providers running in places they were not built for.

Registration

After activating the farm feature using IsUsedByDefault, we still need to do this. We have chosen to do this using a custom PowerShell script. We run this script from our Project Installer (more about that later).

param($RedactieUrl, $ClaimProviderName)

$snapin = Get-PSSnapin | Where-Object {$_.Name -eq 'Microsoft.SharePoint.Powershell'}

if ($snapin -eq $null)

{

          Write-Host "Loading Microsoft SharePoint Powershell Snapin"

          Add-PSSnapin "Microsoft.SharePoint.Powershell"

}

 

function RegisterClaimProviderOnZone {

       param($WebApplication, $Zone, $ClaimProviderName)

       if ($WebApplication.IisSettings.ContainsKey($Zone))

       {

             $settings = $WebApplication.GetIisSettingsWithFallback($Zone)

             $providers = $settings.ClaimsProviders

             if( -not( $providers.Contains($ClaimProviderName))) {

                    $providers += $ClaimProviderName

                    Set-SPWebApplication -Identity $WebApplication `

                           -Zone $Zone `

                           -AdditionalClaimProvider $providers

                    Write-Host "Registered $ClaimProviderName on $($WebApplication.Url) in zone $Zone"

             }else {

                    Write-Host "$ClaimProviderName already registered on $($WebApplication.Url) in zone $Zone"

             }

       }

}

$WebApplication = Get-SPWebApplication $RedactieUrl

RegisterClaimProviderOnZone $WebApplication "Default" $ClaimProviderName

RegisterClaimProviderOnZone $WebApplication "Internet" $ClaimProviderName

It runs just after installing the WSP and activation of the farm feature. We run this script file supplying 2 parameters: the url of the web application and the name of the claim provider. In this case, the claim provider gets registered on both the default zone and the internet zone. We have different claim providers that just get registered on the internet zone. When we first started registering our providers, we had a different implementation of our registration script, and this has caused us some headaches. The main reason was our mis-interpretation of the name of the AdditionalClaimProvider of the Set-SPWebApplication cmdlet. We assumed we could pass a new claim provider and the command would add that new provider to the current collection. That is not the case! The parameter you pass IS the new collection.

This is the way NOT to do it:

$claimProvider = Get-SPClaimProvider $ClaimProviderName

Set-SPWebApplication -Identity $RedactieUrl `

             -Zone $Zone `

             -AdditionalClaimProvider $claimProvider

Everything worked fine until the point we needed to register the second claim provider in a web application. After running the installation of site B, site A suddenly stopped working. Took us some time to realize what happened and that our registration caused the issue. Glad we found this in our test-environment

LESSON 2: When you build and deploy custom claim providers, regression testing is very important, especially if you create providers that are available farm wide of multiple providers are registered in the same web application. Test if your registration works properly and if all providers still work as expected.

Hey, where did my claim providers go?

In our project installation, 95% of the work we need to do is scripted. But we all know the situations where something goes wrong, and you manually tweak some settings here and there. In this case we had to manually set the Custom Signin Page on the Edit Authentication page (Authentication Providers button in the ribbon). And by doing that, we lost the custom claim provider registrations on our web application zone( s ). Of course that happened in a pretty narrow installation window and suddenly our users did not get their claims. Oops. It took us some time to find we lost the registration of the provider and why we lost them.

Another reason why we have lost our providers, is the de-activation of the farm feature. Still hard to find out why the feature was de-activated, but a number of times, we needed to re-activate the feature.

We now have a custom script that makes it real easy to check (thanks Wouter!). If checks whether a specific provider is available in the farm and if it is registered for the Internet zone of a specific web app:

param(

                [string]$Url

)

$Provider = Get-SPClaimProvider | ? {$_.DisplayName -eq "Our custom Claims"} | Select -First 1

$HasProvider = $Provider -ne $null

Write-Host "Claim Provider exists: $HasProvider"

$WebApplication = Get-SPWebApplication $Url

$IisSettings = $WebApplication.GetIisSettingsWithFallback("Internet")

$HasRegisteredClaimProvider = $IisSettings.ClaimsProviders.Contains("OurCustomClaimProvider")

Write-Host "Our Claim Provider is registered: $HasRegisteredClaimProvider"

And if something is broken, there is a script that fixes it. It is the same as the script above, with an extra feature activation action to activate the farm feature.

LESSON 3: If you register your claims provider on a specific web application – zone, never touch the Edit Authentication page, or run your scripts afterwards to re-register the providers.

Context

A claim provider does have context. But only in a number of methods, where you get a context parameter. And be aware, this context is the web application, it is NOT the url of the site collection your user is using. Please be aware that methods without the context parameter can and will be called without any context. So there is no SPContext.Current and no HttpContext.Current. We wanted to read a setting for our claim provider that was site collection specific, but after many tries (and errors and unexpected behavior) we decided it was not the way to go. In some methods you will have a current context, but it is only in a limited number of methods, and you cannot be 100% sure of having that context.

LESSON 4: When designing your claim provider, first study the methods of SPClaimProvider and the context the claim provider gives you. Live with the fact the the only context you will get is the url of the web application, in some of the methods.

Debugging

LESSON 5: When you use custom claims, make sure you have a custom page or webpart in place that shows you the claims the current user has. This MSDN page has an example. You will need it for troubleshooting purposes. We have created a _LAYOUTS page that is deployed by our internal platform installation. That is easy, because this way the page is always available in all websites, and can be used to troubleshoot multiple different claim providers. And we don’t need administrative permissions to clutter the content with a webpart on a page.

Permanent link to this article: http://www.tonstegeman.com/blog/2012/01/custom-claim-providers-for-sharepoint-lessons-learned/

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>