Writing your own Trusted Identity provider for SP2010 (2)

This is part two of a Multi Blog post on "writing your own Trusted Identity provider / Claim Provider for SP2010".
In the first post I covered:

In this post I will cover:

Create a Custom SPClaimProvider

For SharePoint 2010 to Trust any Identity Provider, we need a SPClaimProvider specific for that provider. This SPClaimProvider has two main purposes:

  • Provide a way for SharePoint to communicate with any Trusted Identity Provider in a uniform (Interface) way.
  • And provide SharePoint a way to use the same Claims for Users that have logged in through a different (e.g. AD) Identity Provider, let's call this Claims Augmentation

To create a SPClaimProvider follow the following steps:

  • Create a new VS2010 Empty SP2010 Project
  • And add references to Microsoft.IdentityModel, Microsoft.SharePoint and Microsoft.SharePoint.Security.
  • Create a new Class, let's name it CustomClaimsProvider and inherit from:Microsoft.SharePoint.Administration.Claims.SPClaimProvider
  • Implement all the methods for resolving claims, this is so we can use the claims provided within SharePoint to give rights to claims:
    • FillHierarchy
    • FillResolve
    • FillSearch, FillSchema
    • FillClaimTypes,FillClaimValueTypes,FillEntityTypes
  • Implement FillClaimsForEntity for the claims augmentation
  • Override the SupportsEntityInformation,SupportsHierarchy, ,SupportsResolve and SupportsSearch properties and let them "return True" since we have implemented all the Fill Methods for this SPClaimProvider
  • Give your Provider a Name by overriding the Property Name. You will need this later on.

In fairness, this post has an excellent description on the subject also.
Sample implementation of FillClaimsForEntity

  1: /// <summary>
  2: /// Get's the username part of a claims authentication login claim 
  3: /// figure out who the user is so we know what team to add to their claim
  4: /// the entity.Value from the input parameter contains the name of the 
  5: /// authenticated user. for a SQL FBA user, it looks something like
  6: /// 0#.f|sqlmembership|user1; for a Windows claims user it looks something
  7: /// 0#.w|steve\\wilmaf
  8: /// 0#.t|Customsleden|stef@tamtam.nl
  9: /// </summary>
  10: /// <param name="identityClaims"></param>
  11: /// <returns>only the login part</returns>
  12: public static string GetLoginPartFromIdentityClaim(string identityClaims) {
  13:     string login = identityClaims;
  14:     if (!string.IsNullOrEmpty(login) && login.Contains("|")) {
  15:         string[] parts = login.Split('|');
  16:         if (parts.GetLength(0) == 3) // formsbased or trusted provider based
  17:             login = parts[2];
  18:         if (parts.GetLength(0) == 2) // windows based
  19:             login = parts[1];
  20:     }
  21:     return login;
  22: }
  23:  
  24: /// <summary>
  25: /// Add Claims to a logged in User, from Dynamics CRM info
  26: /// </summary>
  27: /// <param name="context">Current Context, url</param>
  28: /// <param name="entity">the logged in user/claim</param>
  29: /// <param name="claims">The list of claims for the user</param>
  30: protected override void FillClaimsForEntity(Uri context, SPClaim entity, List<SPClaim> claims) {
  31:     if (claims == null)
  32:         throw new ArgumentNullException("claims");
  33:     if (entity == null)
  34:         throw new ArgumentNullException("entity");
  35:  
  36:     Logging.LogMessage(entity.Value);
  37:  
  38:     string login = Utilities.GetLoginPartFromIdentityClaim(entity.Value);
  39:  
  40:     // if windows user, get the email ?
  41:     if (!string.IsNullOrEmpty(login)) {
  42:         Logging.LogMessage(string.Format("User is {0}", login));
  43:  
  44:         CRMClient.Entities.User user = null;
  45:         string email = login;
  46:         if (login.Contains("@")) {
  47:             user = CRMClient.CrmSQLClient.GetUserByEmail(login);
  48:         }
  49:         if (login.Contains("\\")) {
  50:             user = CRMClient.CrmSQLClient.GetUser(login);
  51:             if (user != null)
  52:                 email = user.Email;
  53:         }
  54:         // employee, crm users
  55:         if (user != null) {
  56:             try {
  57:                 Logging.LogMessage(string.Format("User is SystemUser of CRM with an license, Name:{0}", user.FullName));
  58:  
  59:                 claims.Add( GetClaim(CustomClaimsProvider.CustomAccountTypeClaimType, "everyone"));
  60:  
  61:                 SPClaim employee = null;
  62:                 if (user.FullLicense) { // admin and or full license                            
  63:                     employee = GetClaim(CustomClaimsProvider.CustomAccountTypeClaimType, "employee");
  64:                 }
  65:                 else {// readonly 
  66:                     employee = GetClaim(CustomClaimsProvider.CustomAccountTypeClaimType, "employeero");
  67:                 }
  68:                 if (employee != null)
  69:                     claims.Add(employee);
  70:             }
  71:             catch (Exception exc) {
  72:                 Logging.LogException(exc);
  73:             }
  74:         }
  75:         else {
  76:             Logging.LogMessage(string.Format("{0} not found as SYSTEMUSER in CRM", login));
  77:         }
  78:     }
  79: }

Register your Claims Provider for SharePoint

In order for your Claims Provider to be registered within SharePoint 2010 you will need to create a specific type of Feature.

  • Add a Farm Feature to your Project
  • Add an EventReicever to your new Feature
  • And let your receiver inherit from SPClaimProviderFeatureReceiver (see: Register)
  • And now implement the following Properties in your Feature Event Receiver
    • ClaimProviderDisplayName
    • ClaimProviderDescription
    • ClaimProviderAssembly
    • ClaimProviderType

You can use this to return the last two properties:

  1: /// <summary>Get the Full Assembly Name of the Claim provider we want to register</summary>
  2: public override string ClaimProviderAssembly {
  3:     get {
  4:         return typeof(CustomClaimsProvider).Assembly.FullName;
  5:     }
  6: }
  7:  
  8: /// <summary>Get the Class Type of the Claim provider we want to register</summary>
  9: public override string ClaimProviderType {
  10:     get {
  11:         return typeof(CustomClaimsProvider).FullName;
  12:     }
  13: }

That's it, you can now register your Claims Provider, and if you want you can use this as is.
Next post will be on these subjects:

  • Create a Trust between your Tusted Identity Provider (STS) and SharePoint 2010
  • Create or Configure your SP2010 WebApplication to use the Tusted Identity Provider