Claims Walkthrough: Creating Claims Providers for Forms-Based Authentication Web Applications for SharePoint 2010

Summary:  Learn how to create a claims provider for a Microsoft SharePoint 2010 forms-based authentication web application.

Applies to: Business Connectivity Services | Open XML | SharePoint Designer 2010 | SharePoint Foundation 2010 | SharePoint Online | SharePoint Server 2010 | Visual Studio

Provided by:  Andy Li, Microsoft Corporation

Contents

  • Overview of Creating a Claims Provider for a Forms-Based Authentication Web Application

  • Scenario: Using Claims to Access SharePoint Resources

  • Conclusion

  • Appendix A: Identity Claim Encoding Characters Map

  • Additional Resources

Click to get code Download code: ClaimsExample-ContosoClaimsProviders

Overview of Creating a Claims Provider for a Forms-Based Authentication Web Application

In this walkthrough, you implement a sample customer relationship management (CRM) claims provider for the forms-based web application that you created in Claims Walkthrough: Creating Forms-Based Authentication for Claims-Based SharePoint 2010 Web Applications Using Custom Membership and Role Providers. Then, you modify the claims provider to provide additional CRM claims (by using claims augmentation) that are used to control access to SharePoint resources by using an access control list (ACL).

By default, claims search and resolve work with membership and role providers that implement the interfaces that Microsoft SharePoint Foundation 2010 and Microsoft SharePoint Server 2010 call from the default claims provider for forms-based authentication. There may be cases where additional claims are needed (for example, for CRM as described in the scenario section). In such cases, you can use an augmentation claims provider.

The term claims augmentation applies to any type of claims authentication: Windows claims authentication, Security Assertion Markup Language (SAML) sign-in, and forms-based authentication.

Note

For more information about claims augmentation, see Claims Walkthrough: Writing Claims Providers for SharePoint 2010.

Scenario: Using Claims to Access SharePoint Resources

Suppose that you have an external CRM system that has a completely different set of account settings. When logging on to the CRM system, a user provides a different set of user name and password. After logging on, the CRM system grants each user different permissions based on their account setting.

For example, each CRM account has two attributes: Role and Region. The Role attribute indicates whether the current user is a sales representative, a sales manager, or an executive. The Region attribute indicates where the user is located.

In Microsoft SharePoint 2010, there is a site collection for storing documents that are related to CRM. The idea is, when a user logs on to the SharePoint site, we want to bring over their role and region information from the CRM system so that we can enforce permissions on documents based on their CRM role and region information.

Step 1: Preparing the Project

First, you prepare the SharePoint project.

To prepare the project

  1. Create an empty SharePoint project.

  2. Name the project ContosoClaimProviders.

  3. When asked for the SharePoint site for debugging, type http://intranet.contoso.com:200. This is where you have the forms-based authentication claims enabled.

  4. Add a reference to the Microsoft.IdentityModel.dll assembly.

Step 2: Adding the User Lookup Function

Next, you add a function to look up user information.

To add the user lookup function

  1. Add a class file named CRMClaimTypes.cs to the project.

  2. Add the following namespaces.

    using Microsoft.SharePoint.Administration;
    using Microsoft.IdentityModel.Claims;
    using System.Collections;
    
  3. Replace the code in the CRMClaimTypes.cs file with the following code. The CRMClaimType class defines the two custom claims that are supported by our claims provider.

    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";
        }
    }
    
  4. Add a class file named CRMUserInfo.cs. The CRMUseInfo class provides the support for the user information lookup. The following code is provided only for demonstration purposes. A production implementation should consider storing user information in a secure place or looking up the data from the directory services or database.

    1. Add the following code to the CRMUseInfo class.

              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\\andy:CRMRole:SalesManager",
                   contoso\\administrator:CRMRole:SalesManager
                 };
      
              private static string[] claimsDB = 
                 {"CRMRole:Reader", 
                  "CRMRole:SalesRepresentative",
                  "CRMRole:SalesManager",
                  "CRMRole:Executive",
                  "CRMRole:Administrator",
                  "CRMRegion:Northwest",
                  "CRMRegion:East",
                  };
      
    2. Add a static method named GetClaimsForUser. This is a utility method that returns all claims for a specific user.

              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;
              }
      
    3. Add a static method named GetAllUsers. This is another utility method that returns all the account names of a user.

              // Manually constructs a list of users. In a real-world 
              // production environment, you should look up a directory service
              // or database to retrieve the user information.
              public static List<string> GetAllUsers()
              {
                  List<string> allUsers = new List<string>();
      
                  // Add forms users.
                  allUsers.Add("bob");
                  allUsers.Add("mary");
                  allUsers.Add("jack");
                  allUsers.Add("admin1");
      
                  // Add Windows domain user if you want this provider
                  // to augment the claims.
                  allUsers.Add("contoso\\andy");
                  return allUsers;
              }
      
    4. Add the following two methods to the CRMUserInfo class.

      The GetAllClaims method returns all known claims values supported by this provider. All values are defined in the claimsDB string array.

      The GetClaimTypeForRole utility method translates a claim type from its string name to the actual claim type. For example, CRMRole becomes http://schemas.sample.org/ws/2009/12/identity/claims/CRMRole.

              /// <summary>
              /// This method returns all the known claims from the CRM system  
              /// so that the claims provider is able to search and resolve 
              /// the claims in People Picker.
              /// </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!");
              }
      

Step 3: Creating the Claims Provider

Next, you implement a claims provider.

To implement the claims provider

  1. Add a class file named CRMClaimProvider.cs.

  2. Add the following namespaces.

    using Microsoft.SharePoint.Administration.Claims;
    using Microsoft.IdentityModel.Claims;
    using System.Collections;
    using Microsoft.SharePoint.WebControls;
    
  3. Modify the inheritance of the CRMClaimProvider class to be the SPClaimProvider class.

    public class CRMClaimProvider : SPClaimProvider
    
  4. Add the following code to support the construction of the Name property.

            public CRMClaimProvider(string displayName)
                : base(displayName)
            {
            }
    
            public override string Name
            {
                get { return "ContosoCRMClaimProvider"; }
            }
    
  5. Add the following code to the class. As the property names suggest, the properties return either true or false to support each specific method.

    Note

    For an example about how to implement hierarchy, see Claims Walkthrough: Writing Claims Providers for SharePoint 2010.

           /// <summary>
            /// Return true if you are doing claims augmentation.
            /// </summary>
            public override bool SupportsEntityInformation
            {
                get { return true; }
            }
    
            /// <summary>
            /// Return true if you support claims resolution in the People Picker.
            /// </summary>
            public override bool SupportsResolve
            {
                get { return true; }
            }
    
            /// <summary>
            /// Return true if you support claims search in the People Picker.
            /// </summary>
            public override bool SupportsSearch
            {
                get { return true; }
            }
    
            /// <summary>
            /// Return true if you support hierarchy display in the People Picker.
            /// </summary>
            public override bool SupportsHierarchy
            {
                get { return false; }
            }
    
                    public override bool SupportsUserSpecificHierarchy
            {
                get
                {
                    return base.SupportsUserSpecificHierarchy;
                }
            }
    
  6. Add the following methods to the class:

    • FillClaimTypes   Called by SharePoint 2010 to retrieve the claim types that are supported by the claims provider.

    • FillClaimValueTypes   Called by SharePoint 2010 to retrieve the corresponding claim value types for each claim type that it supports.

    • FillSchema   Called by the People Picker to get the information that can be displayed on the People Picker.

    • FillEntityTypes   Tells the People Picker the types of claims that the claims provider supports (that is, user or role).

            /// <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 the 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 that are 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);
            }
    
  7. Add the FillClaimsForEntity method to support claims augmentation. This method is called by the SharePoint security token service (STS) after the user is authenticated.

          /// <summary>
            /// Implement this method if the claims provider supports
            /// claims 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");
                }
    
                // Add the role claim.
                SPClaim userIdClaim = SPClaimProviderManager.DecodeUserIdentifierClaim(entity);
    
                // Add claims for users.
                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));
                    }
    
                }
    
            }
    
  8. Add the FillSearch method to support searching claims.

           /// <summary>
            /// Required if you implement the claims search in the People Picker.
            /// </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 ClaimType for 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;
                    searchTree.AddEntity(entity);
                }
    
            }
    
  9. Add the following two FillResolve methods to support claim resolution in the People Picker.

            /// <summary>
            /// Resolve a single claim by using exact match. This method is required
            /// for claim search and for claim 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 ClaimType for the claim type.
                    // For example, if you 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 resolution in the People Picker.
            /// </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 ClaimType for 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);
                }
    
            }
    
  10. Add the following FillHierarchy method. This method is required to implement all the functions for an abstract class.

    Note

    For an example about how to implement hierarchy, see Claims Walkthrough: Writing Claims Providers for SharePoint 2010.

            protected override void FillHierarchy(Uri context, string[] entityTypes, string hierarchyNodeID, int numberOfLevels, SPProviderHierarchyTree hierarchy)
            {
                throw new NotImplementedException();
            }
    
  11. Build the project and correct any errors.

Step 4: Deploying a Claims Provider

Next, you deploy the claims provider.

To deploy the claims provider

  1. In Solution Explorer, add a feature under the Features node. Rename it to be CRMClaimProvider.

  2. Right-click CRMClaimProvider, and then click Add Event Receiver.

  3. Change the Scope of the feature to be Farm.

  4. Add the namespace to the receiver class file.

    using Microsoft.SharePoint.Administration.Claims;
    
  5. Derive the class from SPClaimProviderFeatureReceiver. This base receiver provides the function for registering the claim to the farm.

    public class CRMClaimProviderEventReceiver : SPClaimProviderFeatureReceiver
    
  6. Replace the implementation for the receiver with the following code.

           private string providerDisplayName = "CRM Claims Provider";
            private string providerDescription = "Provides claims from Contoso CRM system";
    
            public override string ClaimProviderAssembly
            {
                get { return typeof(ContosoClaimProviders.CRMClaimProvider).Assembly.FullName; }
            }
            public override string ClaimProviderType
            {
                get { return typeof(ContosoClaimProviders.CRMClaimProvider).FullName; }
            }
            public override string ClaimProviderDisplayName
            {
                get
                {
                    return providerDisplayName;
                }
            }
            public override string ClaimProviderDescription
            {
                get
                {
                    return providerDescription;
                }
            }
    
  7. Build and deploy the project to the farm.

Step 5: Removing Users from the Site

Next, you remove users.

To remove users from a site

  1. Navigate to http://intranet.contoso.com:200.

  2. Log on by using the credentials admin1/pass@word1.

  3. On the Site Actions menu, click Site Settings.

  4. In the Users and Permissions section, click People and groups.

  5. On the left navigation pane, click More.

  6. If they are present, remove bob, mary, and jack.

  7. If they are present, remove Employee, TeamManager, and CEO.

  8. From the drop-down list in the top-right corner, click Sign in as Different User.

  9. Try to log on as Bob, Mary, or Jack. You should get an error message, as shown in Figure 1.

    Figure 1. Access denied error message

    Access denied error message

    Note

    If you are not getting an access denied error message, go back to the previous steps and ensure that you have deleted all users and roles that you added in Step 2: Adding the User Lookup Function.

Step 6: Testing Claim Search Functionality

Next, you should test the functionality of searching for claims.

To test claim search functionality

  1. Navigate to http://intranet.contoso.com:200.

  2. Log on by using the credentials admin1/pass@word1.

  3. On the Site Actions menu, click Site Permissions.

  4. On the ribbon, click Grant Permissions. The Grant Permissions dialog box displays with the Browse icon under Users/Groups, as shown in Figure 2.

    Figure 2. Grant Permissions dialog box with the People Picker icon

    Grant Permissions dialog box

  5. Click the Browse icon to launch the People Picker dialog box, as shown in Figure 3.

    Figure 3. People Picker dialog box

    People Picker

  6. Type sales in the search box, and then click Search. It should display two results, as shown in Figure 4.

    Figure 4. Searching sales-related claims

    Searching sales-related claims

  7. Double-click each of the results to add both of them to the Add field.

  8. Click OK to close the People Picker. You should see the salesmanager role and the salesrepresentative role added to the Users/Groups field, as shown in Figure 5.

  9. Under Grant Permission, select FBA Site Members [Contribute].

    Figure 5. Selecting FBA Site Members (Contributor)

    Selecting FBA Site Members

  10. Click OK.

  11. On the left navigation pane, click FBA Site Members. It should show that the salesmanager and salesrepresentative roles (claims) are added to the FBA Site Members group, as shown in Figure 6.

    Figure 6. Salesmanager and salesrepresentative roles are in the FBA Site Members group

    Salesmanager and salesrepresentative roles

  12. From the drop-down list in the top-right corner, click Sign in as Different User.

  13. Try to log on as Bob or Mary.

  14. Next, try to log on as Jack. Are you able to log on? If log on failed, why?

  15. Now log on by using the credentials admin1/pass@word1.

  16. Repeat step 3 through step 10 of this procedure to add the role of Executive.

  17. Try to log on by using Jack's credentials and see whether you now succeed.

  18. Repeat step 3 through step 10 of this procedure to add the region claims East and Northwest.

  19. Test the log on behavior for East and Northwest.

Step 6.1: Decoding the claims

Next, decode claims.

To decode the claims

  1. On the Site Actions menu, click Site Settings.

  2. In the Users and Permissions section, click People and groups.

  3. On the People and Groups page, click salesmanager to display information pertaining to the salesmanager claim, as shown in Figure 7.

    Note

    If you have not yet added the salesmanager role to the People and Groups page, add it now. For information about how to add the salesmanager role to the People and Groups page, see Step 6: Testing Claim Search Functionality.

    Figure 7. Salesmanager claim

    Salesmanager claim

  4. Look at the Account name and use the encode table in Appendix A: Identity Claim Encoding Characters Map to decipher each character.

Step 7: Testing the Claims Resolution Functionality

Next, test the functionality of claims resolution.

To test the claims resolution functionality

  1. Repeat Step 5: Removing Users from the Site to remove all of the users claims that you added to the site.

  2. Navigate to http://intranet.contoso.com:200.

  3. Log on by using the credentials admin1/pass@word1.

  4. On the Site Actions menu, click Site Permissions.

  5. On the ribbon, click Grant Permissions. The Grant Permissions dialog box with the Browse icon under Users/Groups displays, as shown in Figure 8.

    Figure 8. Grant Permissions dialog box with the People Picker icon

    Grant Permissions dialog box

  6. Type salesmanager in the Users/Groups text box. Click the Check Name icon that is located at the bottom-right of the Users/Groups text box to resolve the name, as shown in Figure 9.

    Figure 9. Resolving the salesmanager claim

    Resolving the salesmanager claim

  7. Click OK to add the salesmanager claim to the FBA Site Members group.

  8. Repeat the previous steps in this procedure to test the log on behavior for Bob, Mary, and Jack.

  9. In the Users/Group text box, type sales to try a wildcard search. More than one entity should be returned, as shown in Figure 10.

    Note

    You cannot specify the claims provider as you can in the Browse dialog box. You may choose to click More Names to bring up the Browse dialog box.

    Figure 10. Wildcard search

    Wildcard search

Step 8: Debugging a Claims Provider

Next, take what you have learned in the previous test steps and debug claims augmentation, and the search and resolve process:

  • If you are debugging the claims augmentation process, for SharePoint security token service (STS), you need to attach to w3wp.exe.

  • If you are debugging claims search or claims resolution for your web application, attach to w3wp.exe.

  • If you made changes to the claims provider, you need to perform an iisreset because Microsoft Visual Studio 2010 does not recycle the SharePoint STS process; the STS process may still reference the old version of the claims provider.

Step 9: Adding Support for a Windows Account

Next, you enable both Windows authentication and forms-based authentication support for http://intranet.contoso.com:200.

To add support for a Windows account

  1. Launch the Central Administration website.

  2. In the left navigation pane, click Security.

  3. Under the General Security section, click Specify authentication providers.

  4. In the Web Application drop-down list, select http://intranet.contoso.com:200.

  5. Under Zone, click Default as shown in Figure 11.

    Figure 11. Authentication Providers page

    Authentication Providers page

  6. Select the Enable Windows Authentication check box, and then select Integrated Windows authentication, as shown in Figure 12.

    Figure 12. Selecting claims authentication types

    Selecting claims authentication types

  7. Click Save.

  8. Run iisreset.

  9. Return to the claims provider source code and ensure that you have your domain account added to the userDB array.

    Note

    In this example, we added the SalesManager role for contoso\administrator.

            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\\andy:CRMRole:SalesManager",
                 contoso\\administrator:CRMRole:SalesManager
               };
    
  10. Navigate to http://intranet.contoso.com:200.

  11. Log on by using the credentials admin1/pass@word1.

  12. On the Site Actions menu, click Site Permissions.

  13. Grant permission to the site to the SalesManager role, if you have not already done so.

  14. In the drop-down list in the top-right corner, click Sign in as Different User.

  15. The Multiple Authentication Selector page appears, as shown in Figure 13.

    Figure 13. Multiple authentication selector page

    Multiple authentication selector page

  16. On the drop-down list, select Windows Authentication. You should be logged on to the site automatically.

    Note

    When you select Windows Authentication, you are redirected to /_windows/default.aspx, which performs a silent NTLM authentication. Then, you are redirected back to the site.

  17. Look at the Claim Viewer Web Part and see what claims have been added for contoso\administrator.

Step 10: Changing the Claims Scope

You will conduct this step on your own. The task is to create a site collection under http://intranet.contoso.com/sites/CRMDocs. Then, add the following to the site:

  • Document Library: CustomerDocs

  • Custom List: East_Customers

We want this claims provider to be the only claims provider that is available for this site.

The goals are:

  • If a user logs on to http://intranet.contoso.com, there should be no CRM claims in the user's claims token. The Claim Viewer Web Part does not display any CRM-related claims.

  • Only users with CRMRole=Reader can log on to the http://intranet.contoso.com/sites/CRMDocs site.

  • Users with CRMRole=Executive can access the CustomerDocs library.

  • Users with CRMRegion=East can access the East_Customers list.

Take what you have learned and complete this task. To help you to understand and remember, you might want to write down your code.

Conclusion

In this walkthrough, you learn how to create a claims provider for a SharePoint 2010 web application that uses forms-based authentication, and test the claims provider that you created.

Appendix A: Identity Claim Encoding Characters Map

Table 1. Claim types encoding

Character

Claim Type

!

SPClaimTypes.IdentityProvider

"

SPClaimTypes.UserIdentifier

#

SPClaimTypes.UserLogonName

$

SPClaimTypes.DistributionListClaimType

%

SPClaimTypes.FarmId

&

SPClaimTypes.ProcessIdentitySID

SPClaimTypes.ProcessIdentityLogonName

(

SPClaimTypes.IsAuthenticated

)

Microsoft.IdentityModel.Claims.ClaimTypes.PrimarySid

*

Microsoft.IdentityModel.Claims.ClaimTypes.PrimaryGroupSid

+

Microsoft.IdentityModel.Claims.ClaimTypes.GroupSid

-

Microsoft.IdentityModel.Claims.ClaimTypes.Role

.

System.IdentityModel.Claims.ClaimTypes.Anonymous

/

System.IdentityModel.Claims.ClaimTypes.Authentication

0

System.IdentityModel.Claims.ClaimTypes.AuthorizationDecision

1

System.IdentityModel.Claims.ClaimTypes.Country

2

System.IdentityModel.Claims.ClaimTypes.DateOfBirth

3

System.IdentityModel.Claims.ClaimTypes.DenyOnlySid

4

System.IdentityModel.Claims.ClaimTypes.Dns

5

System.IdentityModel.Claims.ClaimTypes.Email

6

System.IdentityModel.Claims.ClaimTypes.Gender

7

System.IdentityModel.Claims.ClaimTypes.GivenName

8

System.IdentityModel.Claims.ClaimTypes.Hash

9

System.IdentityModel.Claims.ClaimTypes.HomePhone

<

System.IdentityModel.Claims.ClaimTypes.Locality

=

System.IdentityModel.Claims.ClaimTypes.MobilePhone

>

System.IdentityModel.Claims.ClaimTypes.Name

?

System.IdentityModel.Claims.ClaimTypes.NameIdentifier

@

System.IdentityModel.Claims.ClaimTypes.OtherPhone

[

System.IdentityModel.Claims.ClaimTypes.PostalCode

\

System.IdentityModel.Claims.ClaimTypes.PPID

]

System.IdentityModel.Claims.ClaimTypes.Rsa

^

System.IdentityModel.Claims.ClaimTypes.Sid

_

System.IdentityModel.Claims.ClaimTypes.Spn

`

System.IdentityModel.Claims.ClaimTypes.StateOrProvince

a

System.IdentityModel.Claims.ClaimTypes.StreetAddress

b

System.IdentityModel.Claims.ClaimTypes.Surname

c

System.IdentityModel.Claims.ClaimTypes.System

d

System.IdentityModel.Claims.ClaimTypes.Thumbprint

e

System.IdentityModel.Claims.ClaimTypes.Upn

f

System.IdentityModel.Claims.ClaimTypes.Uri

g

System.IdentityModel.Claims.ClaimTypes.Webpage

Table 2. Claim value types encoding

Character

Claim Type

!

Microsoft.IdentityModel.Claims.ClaimValueTypes.Base64Binary

"

Microsoft.IdentityModel.Claims.ClaimValueTypes.Boolean

#

Microsoft.IdentityModel.Claims.ClaimValueTypes.Date

$

Microsoft.IdentityModel.Claims.ClaimValueTypes.Datetime

%

Microsoft.IdentityModel.Claims.ClaimValueTypes.DaytimeDuration

&

Microsoft.IdentityModel.Claims.ClaimValueTypes.Double

Microsoft.IdentityModel.Claims.ClaimValueTypes.DsaKeyValue

(

Microsoft.IdentityModel.Claims.ClaimValueTypes.HexBinary

)

Microsoft.IdentityModel.Claims.ClaimValueTypes.Integer

*

Microsoft.IdentityModel.Claims.ClaimValueTypes.KeyInfo

+

Microsoft.IdentityModel.Claims.ClaimValueTypes.Rfc822Name

-

Microsoft.IdentityModel.Claims.ClaimValueTypes.RsaKeyValue

.

Microsoft.IdentityModel.Claims.ClaimValueTypes.String

/

Microsoft.IdentityModel.Claims.ClaimValueTypes.Time

0

Microsoft.IdentityModel.Claims.ClaimValueTypes.X500Name

1

Microsoft.IdentityModel.Claims.ClaimValueTypes.YearMonthDuration

Additional Resources

For more information, see the following resources: