Sample 2: Writing a Claims Provider
Applies to: SharePoint Foundation 2010
Writing a Claims Provider
The following sample shows how to write a claims provider. This sample implementation supports entity, resolve, and search, but not hierarchy. You can find a code example that shows how to support hierarchy in the reference topic for the FillHierarchy() method of the SPClaimProvider class.
To write a claims provider, your first step is to create a class that derives from the SPClaimProvider class. This topic assumes that you have read the How to: Create a Claims Provider topic.
For more information about creating a claims provider and for a walkthrough, see Claims Walkthrough: Writing a Claims Provider.
Tip
For an additional code example and more information about the SPClaimProvider class and its members, see SPClaimProvider. Also, check the SharePoint SPIdentity Team Blog and the Share-n-dipity blog regularly for additional samples and updates.
Sample code provided by: Andy Li, Microsoft Corporation.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.IdentityModel.Claims;
using System.Collections;
using Microsoft.SharePoint.WebControls;
namespace ContosoClaimProviders
{
public class CRMClaimProvider : SPClaimProvider
{
public CRMClaimProvider(string displayName)
: base(displayName)
{
}
public override string Name
{
get { return "ContosoCRMClaimProvider"; }
}
/// <summary>
/// Must return true if you are doing claim augmentation.
/// </summary>
public override bool SupportsEntityInformation
{
get { return true; }
}
/// <summary>
/// Return true if you support claim resolve in the People Picker control.
/// </summary>
public override bool SupportsResolve
{
get { return true; }
}
/// <summary>
/// Return true if you support claim search in the People Picker control.
/// </summary>
public override bool SupportsSearch
{
get { return true; }
}
/// <summary>
/// Return true if you support hierarchy display in the People Picker control.
/// </summary>
public override bool SupportsHierarchy
{
get { return false; }
}
public override bool SupportsUserSpecificHierarchy
{
get
{
return base.SupportsUserSpecificHierarchy;
}
}
/// <summary>
/// Implement this method if the claims provider supports claim augmentation.
/// </summary>
/// <param name="context"></param>
/// <param name="entity"></param>
/// <param name="claims"></param>
protected override void FillClaimsForEntity(Uri context, SPClaim entity, List<SPClaim> claims)
{
if (null == entity)
{
throw new ArgumentNullException("entity");
}
if (null == claims)
{
throw new ArgumentNullException("claims");
}
//Adding the role claim.
SPClaim userIdClaim = SPClaimProviderManager.DecodeUserIdentifierClaim(entity);
//Adding claims for user.
List<string> allCRMUsers = CRMUserInfo.GetAllUsers();
if(allCRMUsers.Contains(userIdClaim.Value.ToLower()))
{
List<Claim> userClaims = CRMUserInfo.GetClaimsForUser(userIdClaim.Value.ToLower());
foreach(Claim claim in userClaims)
{
claims.Add(CreateClaim(claim.ClaimType, claim.Value, claim.ValueType));
}
}
}
/// <summary>
/// Returns all the claim types that are supported by this claims provider.
/// </summary>
/// <param name="claimTypes"></param>
protected override void FillClaimTypes(List<string> claimTypes)
{
if (null == claimTypes)
{
throw new ArgumentNullException("claimTypes");
}
// Add the claim types that will be added by this claims provider.
claimTypes.Add(CRMClaimType.Role);
claimTypes.Add(CRMClaimType.Region);
}
/// <summary>
/// Return all claim value types that correspond to the claim types.
/// You must return the values in the same order as in the FillClaimTypes() method.
/// </summary>
/// <param name="claimValueTypes"></param>
protected override void FillClaimValueTypes(List<string> claimValueTypes)
{
if (null == claimValueTypes)
{
throw new ArgumentNullException("claimValueTypes");
}
claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
claimValueTypes.Add(Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
}
/// <summary>
/// Required for People Picker. This tells the People Picker what
/// information is available for the entity.
/// </summary>
/// <param name="schema"></param>
protected override void FillSchema(SPProviderSchema schema)
{
schema.AddSchemaElement(new SPSchemaElement(PeopleEditorEntityDataKeys.DisplayName,
"DisplayName",
SPSchemaElementType.TableViewOnly));
}
/// <summary>
/// Returns the entity type for the claims returned from the claims provider.
/// </summary>
/// <param name="entityTypes"></param>
protected override void FillEntityTypes(List<string> entityTypes)
{
entityTypes.Add(SPClaimEntityTypes.FormsRole);
entityTypes.Add(SPClaimEntityTypes.FormsRole);
}
/// <summary>
/// Required if you implement the claim search for the People Picker control.
/// </summary>
/// <param name="context"></param>
/// <param name="entityTypes"></param>
/// <param name="searchPattern"></param>
/// <param name="hierarchyNodeID"></param>
/// <param name="maxCount"></param>
/// <param name="searchTree"></param>
protected override void FillSearch(Uri context, string[] entityTypes, string searchPattern, string hierarchyNodeID, int maxCount, SPProviderHierarchyTree searchTree)
{
string keyword = searchPattern.ToLower();
Hashtable knownClaims = CRMUserInfo.GetAllClaims();
List<string> knownClaimsList = new List<string>();
//Convert the knownClaims.Key into a List<string> for LINQ query.
foreach (string claim in knownClaims.Keys)
{
knownClaimsList.Add(claim);
}
var claimQuery = knownClaimsList.Where(claim => claim.IndexOf(keyword) >= 0).Select(claim => claim);
foreach (string claimValue in claimQuery)
{
//Get the claim type.
//For example, if you are search "SalesManager", the ClaimType will be
//CRMClaimType.Role
string claimType = CRMUserInfo.GetClaimTypeForRole((string)knownClaims[claimValue]);
PickerEntity entity = CreatePickerEntity();
entity.Claim = CreateClaim(claimType, claimValue, Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
entity.Description = claimValue;
entity.DisplayText = claimValue;
entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue;
entity.EntityType = SPClaimEntityTypes.FormsRole;
entity.IsResolved = true;
searchTree.AddEntity(entity);
}
}
/// <summary>
/// Resolve one single claim by using exact match. This method is required for both
/// claim search and resolve.
/// </summary>
/// <param name="context"></param>
/// <param name="entityTypes"></param>
/// <param name="resolveInput"></param>
/// <param name="resolved"></param>
protected override void FillResolve(Uri context, string[] entityTypes, SPClaim resolveInput, List<PickerEntity> resolved)
{
string keyword = resolveInput.Value.ToLower();
Hashtable knownClaims = CRMUserInfo.GetAllClaims();
if (knownClaims.ContainsKey(keyword))
{
//Get the claim type.
//For example, if you are search "SalesManager", the ClaimType will be
// CRMClaimType.Role. In this case, the keyword is the value of the claim.
string claimValue = keyword;
string claimType = CRMUserInfo.GetClaimTypeForRole((string)knownClaims[keyword]);
PickerEntity entity = CreatePickerEntity();
entity.Claim = CreateClaim(claimType, claimValue, Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
entity.Description = claimValue;
entity.DisplayText = claimValue;
entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue;
entity.EntityType = SPClaimEntityTypes.FormsRole;
entity.IsResolved = true;
resolved.Add(entity);
}
}
/// <summary>
/// Required if you implement claim resolve for the People Picker control.
/// </summary>
/// <param name="context"></param>
/// <param name="entityTypes"></param>
/// <param name="resolveInput"></param>
/// <param name="resolved"></param>
protected override void FillResolve(Uri context, string[] entityTypes, string resolveInput, List<PickerEntity> resolved)
{
string keyword = resolveInput.ToLower();
Hashtable knownClaims = CRMUserInfo.GetAllClaims();
List<string> knownClaimsList = new List<string>();
//Convert the knownClaims.Key into a List<string> for LINQ query.
foreach (string claim in knownClaims.Keys)
{
knownClaimsList.Add(claim);
}
var claimQuery = knownClaimsList.Where(claim => claim.IndexOf(keyword) >= 0).Select(claim => claim);
foreach (string claimValue in claimQuery)
{
//Get the claim type.
//For example, if you search "SalesManager", the ClaimType will be
//CRMClaimType.Role
string claimType = CRMUserInfo.GetClaimTypeForRole((string)knownClaims[claimValue]);
PickerEntity entity = CreatePickerEntity();
entity.Claim = CreateClaim(claimType, claimValue, Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
entity.Description = claimValue;
entity.DisplayText = claimValue;
entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue;
entity.EntityType = SPClaimEntityTypes.FormsRole;
entity.IsResolved = true;
resolved.Add(entity);
}
}
protected override void FillHierarchy(Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, SPProviderHierarchyTree hierarchy)
{
throw new NotImplementedException();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ContosoClaimProviders
{
public class CRMClaimType
{
public static string Role = "http://schemas.sample.org/ws/2009/12/identity/claims/CRMRole";
public static string Region = "http://schemas.sample.org/ws/2009/12/identity/claims/CRMRegion";
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.IdentityModel.Claims;
using System.Collections;
namespace ContosoClaimProviders
{
public class CRMUserInfo
{
/// <summary>
/// A real-world implementation should look up a directory service or database
/// to retrieve a user’s claim.
/// The code below is used only for demostration purposes.
/// </summary>
/// <param name="username"></param>
/// <returns></returns>
public static List<Claim> GetClaimsForUser(string username)
{
List<Claim> userClaims = new List<Claim>();
foreach(string userInfo in userDB)
{
string[] claims = userInfo.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
if (username == claims[0])
{
userClaims.Add(new Claim(GetClaimTypeForRole(claims[1]), claims[2], Microsoft.IdentityModel.Claims.ClaimValueTypes.String));
}
}
return userClaims;
}
//Manually construct a list of users. In a real-world production environment,
//you should look up a directory serivce or database to retrieve the user information.
public static List<string> GetAllUsers()
{
List<string> allUsers = new List<string>();
//Adding Forms users.
allUsers.Add("bob");
allUsers.Add("mary");
allUsers.Add("jack");
allUsers.Add("admin1");
//Add Windows domain user, if you want this provider
//to support Windows claim mode.
allUsers.Add("contoso\\myalias");
return allUsers;
}
/// <summary>
/// This function returns all the known claims from the CRM system so that
/// the claims provider is able to search and resolve
/// the claims in the People Picker control.
/// </summary>
/// <returns></returns>
public static Hashtable GetAllClaims()
{
Hashtable knownClaims = new Hashtable();
foreach(string claimItem in claimsDB)
{
string[] claim = claimItem.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries);
knownClaims.Add(claim[1].ToLower(), claim[0].ToLower());
}
return knownClaims;
}
public static string GetClaimTypeForRole(string roleName)
{
if (roleName.Equals("CRMRole", StringComparison.OrdinalIgnoreCase))
return CRMClaimType.Role;
else if (roleName.Equals("CRMRegion", StringComparison.OrdinalIgnoreCase))
return CRMClaimType.Region;
else
throw new Exception("CRM Claim Type not found!");
}
private static string[] userDB =
{
"bob:CRMRole:Reader",
"bob:CRMRole:SalesRepresentative",
"bob:CRMRegion:NorthWest",
"mary:CRMRole:Reader",
"mary:CRMRole:SalesManager",
"mary:CRMRegion:East",
"jack:CRMRole:Reader",
"jack:CRMRole:Executive",
"jack:CRMRegion:East",
"admin1:CRMRole:Administrator",
"contoso\\myalias:CRMRole:SalesManager"
};
private static string[] claimsDB =
{"CRMRole:Reader",
"CRMRole:SalesRepresentative",
"CRMRole:SalesManager",
"CRMRole:Executive",
"CRMRole:Administrator",
"CRMRegion:NorthWest",
"CRMRegion:East",
};
}
}