Claims Walkthrough: Creating Claims Providers for Trusted Login Providers for SharePoint 2010

Summary:  Learn how to create a claims provider for a trusted login provider, which is an external (that is, external to SharePoint) security token service (STS) that SharePoint trusts.

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 Trusted Login Provider

  • Step 1: Creating the Claims Provider Project

  • Step 2: Creating the WingtipUserInfo Class That Stores User Information and Can Be Used to Query User Claims

  • Step 3: Adding Code for Claims Augmentation

  • Step 4: Adding Code for Searching Claims

  • Step 5: Adding Code for Claims Resolution

  • Step 6: Registering the WingtipClaimProvider with WingipSTS

  • Step 7: Test the Claims Provider

  • Conclusion

  • Additional Resources

Click to get code Download code: SharePoint 2010 Creating Claims Providers for Trusted Login Providers.zip

Overview of Creating a Claims Provider for a Trusted Login Provider

In Claims Walkthrough: Creating Trusted Login Providers (SAML Sign-in) for SharePoint 2010, we did not create a claims provider for the trusted login provider. We asked Microsoft SharePoint 2010 to generate a SPTrustedClaimProvider object for resolving, listing, and searching claims from the trusted login provider. The available claims are hard-coded when the SPTrustedLoginProvider object, for example, idClaim.AddKnownClaimValue("user1@wingtip.com"), is created and registered.

In this example, we create a custom claims provider for the WingtipSTS. This sample uses an in-memory string array to store users and claims information. A real-world implementation should consider querying a directory service to store user information in a database.

Note

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

By default, SharePoint 2010 does not offer search and resolve in People Picker for trusted login providers. Therefore, anything that the user types in the People Picker, the People Picker returns as it was typed. This can create problems, for example, if access is added for a user but the user still does not have access. But, as of today, there is no industry standard or protocol that enables search and resolve. Even if there was a standard or protocol, in some scenarios, this functionality may not be available. For example, Windows Live ID has scenarios where search is not allowed for privacy reasons.

The solution to this problem is a custom claims provider. A custom claims provider can implement a specific protocol to enable search and resolve (if available) or can just perform basic validation on what the user typed to prevent errors. For example, if the trusted login provider is for granting Contoso users access to the Fabrikam company website, but Contoso does not have a protocol or service that can be used for search and resolve, then the custom claims provider can be used to validate, for example, that email addresses always have the postfix "@contoso.com".

Notice that during registration, the name of the claims provider must match the name of the trusted login provider. The reason for this is that the issuer value for claims that come from the trusted login provider is the name of that trusted login provider. During picking, if the custom claims provider has a different name, then the claims added by that claims provider via the People Picker will have a different "issuer" value. Therefore, during authorization there will be a mismatch. For more information, see Replacing the Out of Box Name Resolution in SharePoint 2010—Part 2.

Changing the assigned claims provider for the trusted login provider is important because, otherwise, the default claims provider will be used in addition to the custom claims provider, which can cause confusion. For more information about changing the assigned claims provider for the trusted login provider, see How to Override the Default Name Resolution and Claims Provide in SharePoint 2010.

This article and walkthrough example targets solving the issue about search and resolution for trusted login providers. In addition, a user may also add a custom claims provider for augmentation, which is not shown in this article. Having a claims provider to solve search and resolve for this case and a second claims provider for claims augmentation (in a CRM scenario) is a valid configuration.

Note

A trusted login provider is an external (that is, external to SharePoint) security token service (STS) that SharePoint trusts. For information about claims terms definitions, see Claims-Based Identity Term Definitions.

SAML passive sign-in describes the process of signing in. When a sign-in for a web application is configured to accept tokens from a trusted login provider, this type of sign-in is called SAML passive sign-in. For more information, see Incoming Claims: Signing into SharePoint.

Step 1: Creating the Claims Provider Project

  1. Open the TrustedLogin solution download code that accompanies this article. It should contain three projects, as shown in Figure 1:

    • TestRPWeb website

    • WingtipSTS website

    • RegisterSTS WinForm application

      Figure 1. Three projects included in the TrustedLogin solution

      Three projects included in TrustedLogin solution

  2. In Solution Explorer, right-click the TrustedLogin solution, select Add, and then click New Project.

  3. Under Visual C#, select the Empty SharePoint Project template, select SharePoint, and then click 2010. Name the SharePoint project WingtipClaimProvider. Then, do the following:

  4. In the WingtipClaimProvider project, add a reference to Microsoft.IdentityModel.dll.

    For more information about Microsoft.IdentityModel.dll, see Windows Identity Foundation.

  5. Right-click the WingtipClaimProvider project, select Add, and then click New Item.

  6. Add a new class file to the project, named WingtipClaimTypes.cs.

  7. The WingtipClaimTypes.cs file defines the claim types that are supported by this claims provider. Replace the code in the WingtipClaimTypes.cs file with the following code. Notice that we added one additional claim type: department.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace WingtipClaimProvider
    {
        public class WingtipClaimType
        {
            public static string EmailAddress = 
            "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
            public static string Title = 
            "http://schemas.wingtip.com/sharepoint/2009/08/claims/title";
            public static string Department = 
            "http://schemas.wingtip.com/sharepoint/2009/08/claims/department";
        }
    }
    

Step 2: Creating the WingtipUserInfo Class That Stores User Information and Can Be Used to Query User Claims

  1. In the project, add a new class file named WingtipUserInfo.cs, as shown in Figure 2.

    Figure 2. Adding a new class file to the WingtipClaimProvider project

    Adding a new class file to WingtipClaimProvider

  2. Replace the using statement with the following code.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.SharePoint.Administration;
    using Microsoft.IdentityModel.Claims;
    using System.Collections;
    
  3. Add the following two string arrays to the WingtipUserInfo class. These two string arrays serve as the user information store.

    • The userDB string array contains the user information and associated claims. (Email address is used as the identifier of the user.)

    • The claimsDB string array contains the available claims that can be searched by this claims provider.

            private static string[] userDB = 
               {
                "user1@wingtip.com:Email:user1@wingtip.com", 
                "user2@wingtip.com:Email:user1@wingtip.com", 
                "user3@wingtip.com:Email:user1@wingtip.com", 
                "user1@wingtip.com:Title:Engineer", 
                "user2@wingtip.com:Title:Manager", 
                "user3@wingtip.com:Title:CEO", 
                "user1@wingtip.com:Department:Finance", 
                "user2@wingtip.com:Department:IT", 
                "user3@wingtip.com:Department:AP", 
               };
    
            private static string[] claimsDB = 
               {
                "Email:user1@wingtip.com", 
                "Email:user2@wingtip.com",
                "Email:user3@wingtip.com",
                "Title:Employoee",
                "Title:Manager",
                "Title:NorthWest",
                "Department:Finance",
                "Department:IT",
                "Department:AP"
               };
    
  4. Add the following code to the WingtipUserInfo class. These functions are just utility functions that read and parse information from userDB and claimsDB. They are used for resolving, searching, and listing claims.

            /// <summary>
            /// A real-world implementation should look up a directory service 
            /// or database to retrieve a user claim.
            /// The following code is used only for demonstration 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 from a directory service or database to 
            // retrieve the user information.
            public static List<string> GetAllUsers()
            {
                List<string> allUsers = new List<string>();
    
                // Adding forms-based users.
                allUsers.Add("user1@wingtip.com");
                allUsers.Add("user2@wingtip.com");
                allUsers.Add("user3@wingtip.com");
    
                // Adding Windows domain users, if you want this provider to 
                // support Windows claims mode.
                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.
            /// </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("Email", StringComparison.OrdinalIgnoreCase))
                    return WingtipClaimType.EmailAddress;
                else if (roleName.Equals("Title", StringComparison.OrdinalIgnoreCase))
                    return WingtipClaimType.Title;
                else if (roleName.Equals("Department", 
                StringComparison.OrdinalIgnoreCase))
                    return WingtipClaimType.Department;
                else
                    throw new Exception("Claim Type not found!");
            }
    

Step 3: Adding Code for Claims Augmentation

  1. Add a new class file named ClaimProvider.cs.

  2. Replace the using statements with the following code.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Microsoft.SharePoint.Administration.Claims;
    using Microsoft.SharePoint.Administration.Claims;
    using Microsoft.SharePoint.WebControls;
    using Microsoft.IdentityModel.Claims;
    
  3. Change the class inheritance to match the following code.

        class ClaimProvider: SPClaimProvider
    
  4. Add a constructor and two properties.

            public ClaimProvider(string displayName)
                : base(displayName)
            {
            }
    
            public override string Name
            {
                get { return "WingtipClaimProvider"; }
            }
    
            // The AssociatedTrustedLoginProviderName property is used for 
            // generating the SPClaim object. 
            public string AssociatedTrustedLoginProviderName
            {
                get { return "WingtipSTS";  }
            }
    
  5. Add support for claims augmentation, search, and resolve.

          /// <summary>
            /// Must return true if you are doing claims augmentation.
            /// </summary>
            public override bool SupportsEntityInformation
            {
                get { return true; }
            }
    
            /// <summary>
            /// Return true if you support claims resolve 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 function to provide the Claim Types information.

    Notice that in FillEntityTypes, we support both User and FormRoles. You must return the entity type for each of the claim types that you support. In this case, EmailAddress is treated as an identity claim (SPClaimEntityTypes.User), and the other two claim types are treated as roles (SPClaimEntityTypes.FormRole).

            /// <summary>
            /// Returns all the claims types that are supported by this 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(WingtipClaimType.EmailAddress);
                claimTypes.Add(WingtipClaimType.Title);
                claimTypes.Add(WingtipClaimType.Department);
            }
    
            /// <summary>
            /// Return all claim value types that correspond to the claim types.
            /// You must return the values in the same order as 
            /// in FillClaimTypes(). 
            /// </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);
                claimValueTypes.Add
                (Microsoft.IdentityModel.Claims.ClaimValueTypes.String);
            }
    
            /// <summary>
            /// Required for the People Picker.
            /// 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.User);
                entityTypes.Add(SPClaimEntityTypes.FormsRole);
                entityTypes.Add(SPClaimEntityTypes.FormsRole);
            }
    
  7. Add the following utility function, which is used to generate the claim object.

    Note

    We explicitly specify that the issuer of the claim is WingtipSTS (not WingtipClaimProvider).

            // The claim from this provider should have WingtipSTS as the 
            // provider name.
            private SPClaim CreateClaimForSTS(string claimtype, string claimValue)
            {
    
                SPClaim result = new SPClaim(claimtype,
                                            claimValue, 
                      Microsoft.IdentityModel.Claims.ClaimValueTypes.String, 
                      SPOriginalIssuers.Format
                                      (SPOriginalIssuerType.TrustedProvider, 
                                       AssociatedTrustedLoginProviderName));
    
                return result;
            }
    
  8. Add the FillClaimsForEntity function to support claims augmentation.

          /// <summary>
            /// Implement this method if the 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");
                }
    
                //Adding the role claim.
                SPClaim userIdClaim = 
                SPClaimProviderManager.DecodeUserIdentifierClaim(entity);
    
                //Adding claims for users.
                List<string> allWingtipUsers = WingtipUserInfo.GetAllUsers();
    
                if (allWingtipUsers.Contains(userIdClaim.Value.ToLower()))
                {
                    List<Claim> userClaims = 
                    WingtipUserInfo.GetClaimsForUser
                    (userIdClaim.Value.ToLower());
                    foreach (Claim claim in userClaims)
                    {
                        claims.Add(CreateClaimForSTS(claim.ClaimType, claim.Value));
                    }
    
                }
    
            }
    

Step 4: Adding Code for Searching Claims

  1. Add the FillSearch method to support searching claims.

    Notice the highlighted part of the function. When a user searches for email address, we return the identity claim; otherwise, we return the role claim.

    Note

    We use LINQ query to support wildcard search in this case.

           /// <summary>
            /// Required if you implement the claims search for 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 = WingtipUserInfo.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 for "SalesManager", 
                    //the ClaimType will be CRMClaimType.Role.
    
                    string claimType = WingtipUserInfo.GetClaimTypeForRole((string)
                    knownClaims[claimValue]);
    
                    PickerEntity entity = CreatePickerEntity();
                    entity.Claim = CreateClaimForSTS(claimType, claimValue);
                    entity.Description = claimValue;
                    entity.DisplayText = claimValue;
                    entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = 
                    claimValue;
    
                    if (string.Compare(claimType, WingtipClaimType.EmailAddress, 
                    true) == 0)
                    {
                        entity.EntityType = SPClaimEntityTypes.User;
                    }
                    else
                    {
                        entity.EntityType = SPClaimEntityTypes.FormsRole;
                    }
    
    
                    entity.IsResolved = true;
                    searchTree.AddEntity(entity);
                }
    
            }
    

Step 5: Adding Code for Claims Resolution

  1. Add the two FillResolve methods to support resolving claims.

    The code tries to match the keyword with the values in ClaimsDB, and then returns the appropriate data.

          /// <summary>
            /// Resolve one single claim by using exact match. 
            /// This method is required for both claims search
            /// and claims 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 = WingtipUserInfo.GetAllClaims();
    
                if (knownClaims.ContainsKey(keyword))
                {
                    // Get the claim type.
                    // For example, if you search for "SalesManager", the ClaimType 
                    // will be CRMClaimType.Role.
                    // In this case, the keyword is the value of the claim.
                    string claimValue = keyword;
                    string claimType = 
                    WingtipUserInfo.GetClaimTypeForRole((string)knownClaims[keyword]);
    
                    PickerEntity entity = CreatePickerEntity();
                    entity.Claim = CreateClaimForSTS(claimType, claimValue);
                    entity.Description = claimValue;
                    entity.DisplayText = claimValue;
                    entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = 
                    claimValue;
                    if (string.Compare(claimType, WingtipClaimType.EmailAddress, true) 
                    == 0)
                    {
                        entity.EntityType = SPClaimEntityTypes.User;
                    }
                    else
                    {
                        entity.EntityType = SPClaimEntityTypes.FormsRole;
                    }
    
                    entity.IsResolved = true;
                    resolved.Add(entity);
                }
            }
    
    
            /// <summary>
            /// Required if you implement claims resolve for 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 = WingtipUserInfo.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 for "SalesManager", 
                    // the ClaimType will be CRMClaimType.Role.
    
                    string claimType = WingtipUserInfo.GetClaimTypeForRole((string)
                    knownClaims[claimValue]);
    
                    PickerEntity entity = CreatePickerEntity();
                    entity.Claim = CreateClaimForSTS(claimType, claimValue);
                    entity.Description = claimValue;
                    entity.DisplayText = claimValue;
                    entity.EntityData[PeopleEditorEntityDataKeys.DisplayName] = claimValue;
                    if (string.Compare(claimType, WingtipClaimType.EmailAddress, 
                    true) == 0)
                    {
                        entity.EntityType = SPClaimEntityTypes.User;
                    }
                    else
                    {
                        entity.EntityType = SPClaimEntityTypes.FormsRole;
                    }
                    entity.IsResolved = true;
                    resolved.Add(entity);
                }
    
            }
    
  2. Add the following FillHierarchy method showing that we are not supporting hierarchy.

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

Step 6: Registering the WingtipClaimProvider with WingipSTS

During registration, the name of the claims provider must match the name of the trusted login provider. The reason for this is that the issuer value for claims that come from the trusted login provider will be the name of that trusted login provider. During picking, if the custom claims provider has a different name, then the claims added by that claims provider via the People Picker will have a different issuer value. Therefore, during authorization there will be a mismatch. For more information, see Replacing the Out of Box Name Resolution in SharePoint 2010—Part 2.

  1. In Solution Explorer, right-click the Features node, and then click Add a New Feature.

  2. Change the Scope of the feature to Farm.

  3. Right-click Feature1, and then click Add an Event Receiver.

  4. Replace the using statement with the following code.

    using System;
    using System.Runtime.InteropServices;
    using System.Security.Permissions;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Security;
    using Microsoft.SharePoint.Administration.Claims;
    
  5. Change the class inheritance to match the following code.

    public class Feature1EventReceiver :SPClaimProviderFeatureReceiver
    
  6. Add the following code into the class. Leave the other code commented.

            private string providerDisplayName = "Wingtip Claim Provider";
            private string providerDescription = "Provides Claims from Wingtip";
    
            public override string ClaimProviderAssembly
            {
                get { return typeof
                (WingtipClaimProvider.ClaimProvider).Assembly.FullName; }
            }
    
    
            public override string ClaimProviderDisplayName
            {
                get
                {
                    return providerDisplayName;
                }
            }
    
            public override string ClaimProviderType
            {
                get { return typeof(WingtipClaimProvider.ClaimProvider).FullName; }
            }
    
            public override string ClaimProviderDescription
            {
                get { return providerDescription; }
            }
    
            public override bool ClaimProviderUsedByDefault
            {
                get
                {
                    return true;
                }
            }
    
  7. Compile the WingtipClaimProvider project and ensure that it builds successfully.

  8. Right-click the WingtipClaimProvider project, and then click Deploy. This step registers the claims provider with the farm.

  9. Open Form1 in the RegisterSTS project.

  10. Add a button named Update ClaimProvider.

    You should have only two buttons on the form: One is register WingtipSTS and the other is Update ClaimProvider, as shown in Figure 3.

    Figure 3. Form1 showing the Update ClaimProvider button

    Form1 showing the Update ClaimProvider button

  11. In the code-behind of the new button, add the following code.

                SPSecurityTokenServiceManager manager = SPSecurityTokenServiceManager.Local;
    
                string providerName = "WingtipSTS";
    
                SPTrustedLoginProvider provider = manager.TrustedLoginProviders[providerName];
                provider.ClaimProviderName = "WingtipClaimProvider";
                provider.Update();
            }
    
  12. Compile the application and correct any errors.

  13. Right-click the RegisterSTS project, select Debug, and then Start New Instance.

  14. When the application starts, click the Update ClaimProvider button. This updates the claims provider for the WingtipSTS trusted login provider.

Step 7: Test the Claims Provider

Again, ensure that your WingtipSTS project is running and can be accessed via browser.

  1. Launch the Central Administration website.

  2. On the Create Site Collection page (see Figure 4), select https://intranet.contoso.com.

    Figure 4. Create Site Collection page

    Create Site Collection page

  3. In the Site Collection Administrator section, click the Browse icon to launch the People Picker. Notice that you have a "Wingtip Claim Provider" on the left side, as shown in Figure 5. This is the claims provider that you just created.

    Figure 5. The Wingtip Claim Provider as displayed in the People Picker

    Wingtip Claim Provider displayed in People Picker

  4. In the left pane, select Wingtip Claim Provider. Type user in the Search box. Three users should be returned, as shown in Figure 6.

    Figure 6. Searching for "user" returns three users in the People Picker

    Searching for "user" returns three users

  5. Select User1@wingtip.com as the site collection administrator.

  6. Create the site collection under https://intranet.contoso.com/sites/Test1.

  7. After the site collection is created, in your browser, navigate to https://intranet.contoso.com/sites/Test1.

  8. On the WingtipSTS logon page, type in the credential for user1@wingtip.com (the password can be anything), as shown in Figure 7.

    Note

    Ensure that you have WingtipSTS running. If not, right-click the WingtipSTS project, and then select View in Browser.

    Figure 7. The WingtipSTS logon page

    WingtipSTS logon page

  9. Click Submit. You should be redirected back to the SharePoint site. (The first launch might take several moments.)

    Figure 8. Redirected to SharePoint site after successfully logging on

    Redirected to SharePoint site after logging on

  10. On the Site Action menu, select Site Permissions.

  11. On the ribbon, click Grant Permission.

  12. Type IT, and then press Enter. After the name resolves, click IT, and then select it [Wingtip Claim Provider], as shown in Figure 9.

    Figure 9. Selecting "it [Wingtip Claim Provider]"

    Selecting "it [Wingtip Claim Provider]"

  13. Click the Browse icon to open the People Picker dialog box.

  14. Search for AP. Pick the entry that is returned from Wingtip Claim Provider, as shown in Figure 10.

    Figure 10. Selecting "AP" from Wingtip Claim Provider

    Selecting "AP" from Wingtip Claim Provider

  15. Add IT and AP to the Members group (Contributor), as shown in Figure 11.

    Figure 11. Adding "IT" and "AP" to the Members group (Contributor)

    Adding "IT" and "AP" to Members group

  16. Sign out for user1@wingtip.com, as shown in Figure 12, and then close all instances of your browser.

    Note

    This step is important. Ensure that you close all instances of your browser.

    Figure 12. Signing out

    Signing out

  17. Open a new instance of Internet Explorer or another browser, and go to https://intranet.contoso.com/sites/Test1.

  18. Try to log on by using user2@wingtip.com.

  19. Can you log on? Why or why not?

  20. Try to log on by using user3@wingtip.com.

  21. Can you log on? Why or why not?

  22. Create a claim viewer Web Part, and then add it to the home page and display the claims for all three users. (The code for this step is not provided.)

Conclusion

In this walkthrough, you learn how to create a claims provider for a trusted login provider. A trusted login provider is an external STS that SharePoint trusts.

Additional Resources

For more information, see the following resources: