You may find yourself in a scenario where Active Directory isn’t available across your entire solution scope. For example, if you have a solution that perhaps starts out in SharePoint, but then has to go fetch data or other resources from some repository that isn’t secured by the same Active Directory you logged in with (or with any Active Directory). A good example of this today would be if you wanted to make a call out to Windows Azure, and you want to use the security information you got when you connected to your SharePoint site (which IS secured with your local Active Directory). Setting aside for a moment the features of ACS in Azure (which is a much longer and involved discussion), think about the set of claims you get when you hit your SharePoint site.
If you are a Windows user, you get your individual claims and augmented claims from custom providers, and for each Windows group you belong to you get a “groupsid” claim, where the value of the claim is the SID of the group. That all works great when you’re in Active Directory land, but when you go out to some other resource that doesn’t understand or doesn’t have any kind of relationship with your local Active Directory, that SID value is basically meaningless. Now compare that to a SAML token user – when you login there you get your individual claims and augmented claims from custom providers. But for each group you belong to (could be a Windows user that logs via ADFS or any federated user that gets group claims), you get a “role” claim and the value is the name of the group (or it least that’s how it’s most commonly represented).
What’s quite nice about the SAML scenario is now when you go to some other source that doesn’t know your local Active Directory (or whatever your identity provider is), you have a nice ubiquitous set of identifiers – they’re all strings so it’s a lot easier to make authorization decsions. In fact, if you’re writing .NET code you can use these role claims to make permission demands down to the individual methods in your public endpoints. For example, you can place a PrincipalPermission demand that says hey, only Sales Managers should be able to call this method. If a user doesn’t have a claim for that role then they simply get an Access Denied error when trying to call it. Here’s an example of what demand would look like:
[PrincipalPermission(SecurityAction.Demand, Role = “Sales Managers”)]
So that brings us back to the point of this posting – how can we get this same kind of experience for our Windows claims users? Well to try and tackle this, I wrote a small and fairly simple custom claims provider. It simply looks at the identity claim of the user that’s logging in and if it’s a Windows claims user, it will go out to the domain specified in the domain\username attribute and do a couple of lookups. The first lookup gets the distinguishedName of the user, and the second lookup gets all of the group memberships the user has. It’s also worth noting that this code runs in the same process as the SharePoint STS, which is the farm account, so you need to make sure that account has rights to read the domain information for the forest(s) where your users are coming from. The net of this is when you use this provider, your Windows claims users will have one standard “role” claim for each Active Directory group to which they belong. Functionally this makes it very easy to make authorization decisions for ALL of these users now as you slide across different application and data center boundaries.
Rather than trying to describe the code in this post, I’m just attaching the entire project including source code. So if you want to see how it looks, just crack open the project in Visual Studio. If you just want to use the provider then you can take the compiled assembly, register it in the GAC, take the feature (I’ve also included a feature.xml file), register it and go. This is, of course, provided AS-IS, so use as you want.
You can download the attachment here: