Why Custom Claims Provider?Simple ! Claims auth based on Windows based, Forms based or SAML based authentication will generate Claims. But mostly they may not be compatible with the claim information what we / application require.
Below is a claim set generated by STS in case of Claims with Windows.
For example, lets say Date of Birth is part of AD Group, and when user sign in to my site, i will get DOB as one of the claims. But task of my application is to categorize people into Kids (<18 Yrs), Youth (18 to 27), Middle Aged (27 to 40) and so on . . . which will be done by adding one more extra claim with respective values (kids, youth, middle aged . . . ), based on information provided by default claims(Age calculated from DOB). That task will be done by Custom Claim Provider.
Now Custom Claim provider is the layer between Sharepoint STS and My Application, which will act like an adapter.
There are many awesome resources like Articles, Posts and Videos on this specific task. Especially MSDN has a great repository of information. Below is the link.
MSDN Repository
Again Obvious question, then what i will be writing in this post which is different from MSDN?
I have done a very simple example briefing the significance of every pieces of a Claims provider.
Step1: Download the code from the link. It is the code written by Ted Pattison, a well renowned sharepoint security expert.
Step 2: The custom provider class should be Implementing abstract class "SPClaimProvider".
Understand the declarations part where we declare name of claim provider, its type, Value and the name of the custom claim that we gona induce into claims repository provided by STS.
internal const string ClaimProviderDisplayName = "Audience Claim Provider"; internal const string ClaimProviderDescription = "SharePoint 2010 Demoware from Critical Path Training"; protected const string AudienceClaimType = "http://www.wingtip.com/identity/claims/audience"; protected const string StringTypeClaim = Microsoft.IdentityModel.Claims.ClaimValueTypes.String; public override string Name { get { return ClaimProviderDisplayName; } }Step 3: Now observe below 4 properties and 2 methods
public override bool SupportsEntityInformation { get { return true; } } public override bool SupportsHierarchy { get { return true; } } public override bool SupportsResolve { get { return true; } } public override bool SupportsSearch { get { return true; } } protected override void FillClaimTypes(ListThough they look simple, these properties control the execution of the remaining code. For example, SupportSearch property returns true. This means, when a search happens in my sitecollection, the code in my claim provider will be executed instead of default search code in sharepoint.claimTypes) { if (claimTypes == null) throw new ArgumentException("claimTypes"); claimTypes.Add(AudienceClaimType); } protected override void FillClaimValueTypes(List claimValueTypes) { if (claimValueTypes == null) throw new ArgumentException("claimValueTypes"); claimValueTypes.Add(StringTypeClaim); }
Step 4: We have 4 more abstract methods to override.
- FillClaimsForEntity() - Method controls additional claims loaded/created for logged in user
- FillHierarchy() - Method controls the Claim provider hierarchy display in search window.
- FillSearch() - Method controls the search functionality in all people pickers in site collection.
- FillResolve() - Method controls functionality executed when you type in a name and click resolve button (one with green tick mark).
I will add extra claim with claim-type as "http://www.wingtip.com/identity/claims/audience" and Claim-value as their name from this array.internal string[] AvailableClaims = {"administrator","spuser","pratap" };
Step 5: Look at the updated methods with simplest possible code.
protected override voidFillClaimsForEntity (System.Uri context, SPClaim entity, Listclaims) { if (entity == null) throw new ArgumentException("entity"); if (claims == null) throw new ArgumentException("claims"); string userLogin = (entity.Value.Split('\\'))[1]; foreach(string claim in AvailableClaims) { if (userLogin.ToLower()==claim.ToLower()) { claims.Add(CreateClaim(AudienceClaimType, claim, StringTypeClaim)); } } } protected override void FillHierarchy (System.Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, SPProviderHierarchyTree hierarchy) { // No additional nodes need to be added to the People Picker } protected override voidFillSearch (System.Uri context, string[] entityTypes, string searchPattern, string hierarchyNodeID, int maxCount, SPProviderHierarchyTree searchTree) { if (EntityTypesContain(entityTypes, SPClaimEntityTypes.FormsRole)) { Listaudiences = new List (); foreach (string claim in AvailableClaims) { if (claim.StartsWith(searchPattern, StringComparison.CurrentCultureIgnoreCase)) audiences.Add(claim); } foreach (string audienceName in audiences) searchTree.AddEntity(CreatePickerEntityForAudience(audienceName)); } } protected override void FillResolve (System.Uri context, string[] entityTypes, string resolveInput, Listresolved) { List audiences = new List (); foreach (string claim in AvailableClaims) { if (claim.StartsWith(resolveInput, StringComparison.CurrentCultureIgnoreCase)) audiences.Add(claim); } foreach (string audienceName in audiences) { resolved.Add(CreatePickerEntityForAudience(audienceName)); } }
Output:
Now when i log into application, below are the claims created because of my code.
Look at the people picker search window changed from what to what.
If you observe we haven't implemented any thing in FillHierarchy() Method as we didn't have any child nodes to display in our claim provider. But you can implement this method if you want to display some thing like below.
Look how the resolving of names got changed.
If you observe the first one is resolved based on my windows credentials. But the second one is resolved based on my claim value.
Last obvious question, what we achieved from this?
Well let me show you. i have a document which has to be displayed for people whose age>18.
we need to do 2 simple things.
- Break default inheritance of permissions on that document.
- Assign the permissions to "Youth" and "MiddleAge" claims.
Demo: I have a document library with 3 documents. I want to show only 2 documents to user Pratap.
Go to those two documents and manage their permissions.
Remove all users from access list and remove permission inheritance.
Add access to specific claim type, in this case to "pratap".
Now, when pratap login, this is how the document library will be displayed.
Task accomplished. We have learned about Custom Claims Provider, significance of each method in it and Importantly how granular level security can be implemented using custom claims.
Download My Sample Code
Is it helpful for you? Kindly let me know your comments / Questions.
Nice Article Dear...
ReplyDeleteSimple explanation. Thanks!
ReplyDeleteCan you tell me how can I get this "Youth" and "MiddleAge" claims. will you please help me ?
ReplyDelete