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",
            };
    }


}