Export (0) Print
Expand All
Expand Minimize

Claims Walkthrough: Creating Trusted Login Providers (SAML Sign-in) for SharePoint 2010

SharePoint 2010

Summary:  Learn how to create a custom security token service (STS) and then set up a trust relationship between a SharePoint 2010 farm and the custom STS.

In this walkthrough, you create a custom security token service (STS) and then set up a trust relationship between a Microsoft SharePoint 2010 farm and the custom STS. The custom STS serves as the authentication provider. When users log on to the SharePoint site, they are first redirected to the logon page of the custom STS. They are redirected back to SharePoint after the authentication.

Note Note

A trusted login provider is an external (that is, external to SharePoint) STS that SharePoint trusts. For definitions of claims terms, 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.

The fictitious company Contoso has a SharePoint site hosted on an extranet, which its employees can log on to remotely from home or during business travel. Contoso has a partner company named Wingtip, whose employees are working on a project with Contoso and who need to access documents from the SharePoint site.

To enable the Wingtip employees to log on to the SharePoint site that is hosted by Contoso, Wingtip created an STS that can be used to authenticate its employees. On the Contoso site, the farm administrator set up the trust relationship between the SharePoint farm and Wingtip's STS. When employees from Wingtip try to log on to the Contoso SharePoint site, they are first redirected to their STS to be authenticated, then the STS redirects the user to the Contoso SharePoint site. Because the SharePoint farm trusts the Wingtip STS, it also trusts the security token that is issued by the Wingtip STS.

  1. Start Visual Studio 2010.

  2. On the File menu, click New Project.

  3. In the New Project dialog box, do the following:

    1. In the left pane, select Other Project Type, click Visual Studio Solution, and then select Blank Solution on the right, as shown in Figure 1.

    2. For Location, type C:\StudentFiles\LabFiles\Module_6\Lab.

    3. For the solution Name, type TrustedLogin.

      Figure 1. New Project dialog box in Visual Studio

      New Project dialog box in Visual Studio
  4. In Solution Explorer, right-click the TrustedLogin solution, click Add, and then click New Web Site.

  5. In the Add New Web Site dialog box, do the following:

    1. Select the ASP.NET Security Token Service Web Site template.

    2. Change Web Location to File System, and the value to C:\StudentFiles\LabFiles\Module_6\Lab\TrustedLogin\WingtipSTS.

      Figure 2. Add New Web Site dialog box in Visual Studio

      Add New Web Site dialog box in Visual Studio
  6. Open the web.config file under the new website. In the appSettings section, change IssuerName to WingtipSTS.

    Figure 3. Change appSettings

    Change appSettings


    Note Note

    The SigningCertificateName (CN=STSTestCert) is the certificate that is used by WingtipSTS to sign the security token.

  7. Click Start, and then click Run.

  8. Type mmc, and then press Enter.

  9. In the Microsoft Management Console, click File, and then click Add/Remove Snap-in.

  10. Under the Available snap-ins field in the left pane, click Certificates, and then click Add.

    Figure 4. Microsoft Management Console displaying the STSTestCert

    MMC displaying the STSTestCert
  11. In the Certificate snap-in dialog box, click Computer Account, click Next, and then select Local Computer.

  12. Click Finish, and then click OK.


    Note Note

    Notice that the SigningCertificate in web.config points to the certificate that is displayed here as STSTestCert.

  13. When setting up the trust between WingtipSTS and SharePoint, we need to tell SharePoint the certificate that is used by WingtipSTS. To do this:

    1. Right-click STSTestCert, select All Tasks, and then click Export.

    2. Click Next. Notice that you can export only the public key from this certificate.

    3. Click Next, and then select DER encoded binary X.509 (.CER).

    4. Click Next. In the File to Export dialog box, type C:\StudentFiles\LabFiles\Module_6\Resources\STSTestCertPub.cert as the file name.

    5. Click Next, and then click Finish.

  14. Close Microsoft Management Console.

  1. Right-click the TrustedLogin solution, click Add, and then click New Web Site.

  2. In the Add New Web Site dialog box, select Claim-Aware ASP.NET Web Site template. Set Web Location to File System and Value to C:\StudentFiles\LabFiles\Module_6\Lab\TestRPWeb, as shown in Figure 5.

    Figure 5. Add New Web Site dialog box

    Add New Web Site dialog box
  3. Right-click the TestRPWeb project, and then click Add STS Reference.

  4. In the Federation Utility wizard that opens, on the Welcome to the Federation Utility wizard page (see Figure 6), click Next. When prompted with The application is NOT hosted on a secure https connection, click Yes.

    Figure 6. Welcome to the Federation Utility wizard page

    Welcome to the Federation Utility wizard page
  5. On the Security Token Service page, click Use an existing STS option. Type http://localhost:48924/WingtipSTS/FederationMetadata/2007-06/FederationMetadata.xml as the STS WS-Federation metadata document location, as shown in Figure 7.

    Note Note

    This URL might be different in your environment. To find the correct URL, right-click FederationMetadata.xml under the FederationMetadata/2007-06 folder in your WingtipSTS project.

    Figure 7. Security Token Services page with STS option

    STS option dialog box
  6. Click Next, and then click Yes regarding the non-secure connection.

  7. On the Security token encryption page, click No Encryption, as shown in Figure 8.

    Figure 8. Security token encryption page

    Security token encryption page
  8. On the Offered Claims page, click Next, as shown in Figure 9.

    Note Note

    This dialog box does not list the claim types that you defined; this is okay.

    Figure 9. Claims offered on the Offered claims page

    Claims offered on the Offered claims page
  9. In the Summary dialog box, click Finish.

    Note Note

    The previous steps will add the necessary entries in the web.config file of WingtipSTS project so that the website will redirect the user to the WingtipSTS site to authenticate the user and to obtain the user's claims.

  10. Open the web.config file.

  11. Remove requestValidationMode="2.0" from the <httpRuntime> element.

  12. Compile the TestRPWeb project and correct any compile errors.

  13. Under TestRPWeb, right-click Default.aspx, and then select View in Browser. You should be redirected to the logon page of the WingtipSTS site, as shown in Figure 10.

    Note Note

    If you get a page cannot be displayed error, ensure that WingtipSTS is up and running in Visual Studio Web Development.

    Figure 10. WingtipSTS logon page

    WingtipSTS logon page
  14. Type the following credentials:

    • Username: user1@wingtip.com

    • Password: pass@word1 (We do not verify the password; any password will work.)

  15. Click Submit. You are redirected back to the TestRPWeb site. Default.aspx displays all claims that are returned by WingtipSTS.

    Figure 11. Claims returned by WingtipSTS

    Claims returned by WingtipSTS

Troubleshooting a Redirection Error

You may receive the following error when WingtipSTS redirects you back to TestRPWeb:

ID4175: The issuer of the Security Token was not recognized by the IssuerNameRegistry. To accept Security Tokens from this issuer, configure the IssuerNameRegistry to return a valid name for this issuer.

If you receive this error, verify that the thumbprint value of the STSTestCert in the web.config file, under TestRPWeb, is correct.

<issuerNameRegistry 
  type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry,
  Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, 
  PublicKeyToken=31bf3856ad364e35">
  <trustedIssuers>
      <add thumbprint="99fcfe2c70ebb571020ca8aa1b7633dfe1fa1d58" name="http://localhost:48924/WingtipSTS/" />
  </trustedIssuers>
</issuerNameRegistry>

To verify this, open the Certificate MMC and find the thumbprint on the Details tab of the certificate, as shown in Figure 12.

Figure 12. Certificate dialog box showing thumbprint

Certificate dialog box showing thumbprint

  1. Add a class file named UserInfo.cs to the App_Code folder under the WingtipSTS Web Site project.

  2. Add the following using statement to UserInfo.cs.

    using Microsoft.IdentityModel.Claims;
    
    
  3. Add the following code at the end of the UserInfo.cs file. The WingtipClaimTypes class defines the claims that are supported by WingtipSTS.

    public class WingtipClaimTypes
    {
        // System.IdentityModel.Claims.ClaimTypes.Email;
        public static string EmailAddress = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
        public static string Title = "http://schemas.wingtip.com/sharepoint/2009/08/claims/title";
    }
    
  4. Replace the UserInfo class with the following code. This class contains some utility methods that are used by WingtipSTS to retrieve a user's claims and authenticate the user based on the user's credentials.

    Note Note

    This code is only for demonstration purposes. You should not use it in a production environment.

    public class UserInfo
    {
        // The email address is used as the UserID.
        // Every user has two claims: title and email address. 
        // SharePoint will pick up the email claim and treat it as the identity.
        private static string[] userDB = 
           {
            "user1@wingtip.com:Title:Engineer", 
            "user1@wingtip.com:Email:user1@wingtip.com",
            "user2@wingtip.com:Title:Manager",
            "user2@wingtip.com:Email:user2@wingtip.com",
            "user3@wingtip.com:Title:CEO",
            "user3@wingtip.com:Email:user3@wingtip.com",
           };
    
        // Manually construct a list of users. In a 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>();
            // Adding forms-based users.
            allUsers.Add("user1@wingtip.com");
            allUsers.Add("user2@wingtip.com");
            allUsers.Add("user3@wingtip.com");
            return allUsers;
        }
    
        public static bool AuthenticateUser(string username, string password)
        {
            // Add your authentication logic here.
            return true;
        }
    
        /// <summary>
        /// A real implementation should look up a directory service or database 
        /// to retrieve a user's claim. The code below 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;
        }
    
        public static string GetClaimTypeForRole(string roleName)
        {
            if (roleName.Equals("Title", StringComparison.OrdinalIgnoreCase))
                return WingtipClaimTypes.Title;
            else if (roleName.Equals("Email", StringComparison.OrdinalIgnoreCase))
                return WingtipClaimTypes.EmailAddress;
            else
                throw new Exception("Claim Type not found!");
        }
    
    }
    
    
  5. The code in the UserInfo.cs file now looks like the following.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using Microsoft.IdentityModel.Claims;
    
    public class WingtipClaimTypes
    {
        // System.IdentityModel.Claims.ClaimTypes.Email;
        public static string EmailAddress = 
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress";
        public static string Title = "http://schemas.wingtip.com/sharepoint/2009/08/claims/title";
    }
    
    public class UserInfo
    {
        // The email address is used as the UserID.
        // Every user has two claims: title and email address. 
        // SharePoint will pick up the email claim and treat it as identity.
        private static string[] userDB = 
           {
            "user1@wingtip.com:Title:Engineer", 
            "user1@wingtip.com:Email:user1@wingtip.com",
            "user2@wingtip.com:Title:Manager",
            "user2@wingtip.com:Email:user2@wingtip.com",
            "user3@wingtip.com:Title:CEO",
            "user3@wingtip.com:Email:user3@wingtip.com",
           };
    
        // Manually construct a list of users. In a 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>();
            //Adding forms-based users.
            allUsers.Add("user1@wingtip.com");
            allUsers.Add("user2@wingtip.com");
            allUsers.Add("user3@wingtip.com");
            return allUsers;
        }
    
        public static bool AuthenticateUser(string username, string password)
        {
            // Add your authentication logic here.
            return true;
        }
    
        /// <summary>
        /// A real implementation should look up a directory service or database 
        /// to retrieve a user's claim. The code below 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;
        }
    
        public static string GetClaimTypeForRole(string roleName)
        {
            if (roleName.Equals("Title", StringComparison.OrdinalIgnoreCase))
                return WingtipClaimTypes.Title;
            else if (roleName.Equals("Email", StringComparison.OrdinalIgnoreCase))
                return WingtipClaimTypes.EmailAddress;
            else
                throw new Exception("Claim Type not found!");
        }
    
    }
    
    
  6. Under App_Code, double-click CustomSecurityTokenService.cs to open the file.

  7. Add the namespace reference to System.Collections.

  8. Replace the GetOutputClaimsIdentity function with the following code. This is the function that returns the user's claim.

        protected override IClaimsIdentity GetOutputClaimsIdentity( IClaimsPrincipal principal, 
             RequestSecurityToken request, Scope scope )
        {
            if ( null == principal )
            {
                throw new ArgumentNullException( "principal" );
            }
    
            ClaimsIdentity outputIdentity = new ClaimsIdentity();
    
            // Issue custom claims.
            // TODO: Change the claims below to issue custom claims 
            // that are required by your application.
            // Update the application's configuration file to reflect 
            // the new claims requirements.
    
            // outputIdentity.Claims.Add( new Claim( 
                System.IdentityModel.Claims.ClaimTypes.Name, principal.Identity.Name ) );
            // outputIdentity.Claims.Add( new Claim( ClaimTypes.Role, "Manager" ) );
    
            // The Wingtip implementation.
            string username = principal.Identity.Name;
            List<Claim> claims = UserInfo.GetClaimsForUser(username);
    
            foreach (Claim claim in claims)
            {
                outputIdentity.Claims.Add(claim);
            }
    
            return outputIdentity;
        }
    
  9. Compile the WingtipSTS website, and then correct any compile errors.

The process of setting up trust between WingtipSTS and SharePoint is basically to register the WingtipSTS as a SPTrustedLoginProvider object in the SharePoint farm.

  1. On the Central Administration site, on the left navigation pane, click Security.

  2. Under General Security, click Manage Trust.

  3. On the Server ribbon, click New.

  4. In the Establish Trust Relationship dialog box, in the Name text box, type STSTestCert so that it will be displayed as shown in Figure 13.

    Figure 13. Establishing trust relationship in Central Administration

    Trust Relationships in Central Administration
  5. Click Browse, and then locate the STSTestCertPub.cer file that you exported earlier.

  6. Click OK.

    Note Note

    Step 4 enables SharePoint to trust all the certificates that are rooted to the STSTestCert certificate.

  7. Add a WinForm project named RegisterSTS to the TrustedLogin solution.

    Note Note

    Ensure that you change the Platform Target to All CPU and .NET Framework to 3.5.

  8. Right-click the RegisterSTS project, and then click Set as Startup Project.

  9. Add a button to the form and change the Text property of the button to Register WingtipSTS.

  10. Double-click the button. This brings you to the event handler function of the button.

  11. Replace the Button1_Click function with the following code. The code creates a SPTrustedLoginProvider object and adds it to the SPSecurityTokenServiceManager.TrustedLoginProviders collection.

    Note Note

    You can also use Windows PowerShell scripts to register an STS with SharePoint. For more information, see Security Cmdlets (SharePoint Foundation 2010).

    The code does the following:

    1. Define the claims that will be recognized by SharePoint (in this example, email and title).

    2. idClaim defines which claim type is used to uniquely identify a user.

    3. The AddKnownClaimValue function of the SPTrustedClaimTypeInformation class adds the known claim values to the claim type so that later on, when you do a claim search in the People Picker, you will be able to find them.

    4. An X509Certificate2 object points to the public key that we exported earlier.

    On the constructor of the SPTrustedLoginProvider class, remember to modify the URI of your WingtipSTS (the port number may be different; the WingtipSTS in this sample is hosted at the URL http://localhost:48924/WingtipSTS/default.aspx).

    Caution note Caution

    Do not forget the default.aspx in the URL.

    You can create a custom SPClaimProvider object for your SPTrustedLoginProvider object and register it by using SPTrustedLoginProvider.ClaimProviderName (commented out in the following code). Otherwise, SharePoint automatically creates an SPTrustdClaimProvider object (derived from the SPClaimProvider class) for this SPTrustedLoginProvider object. This SPTrustdClaimProvider object is based on the claim type information that we provided in the registration code.

    https://intranet.contoso.com/_trust/ is the redirect URL after the user is authenticated by the STS.

           private void button1_Click(object sender, EventArgs e)
            {
                List<SPTrustedClaimTypeInformation> claimMapping = new List<SPTrustedClaimTypeInformation>();
                List<string> strClaimMapping = new List<string>();
    
                SPTrustedClaimTypeInformation idClaim = new SPTrustedClaimTypeInformation("EmailAddress", 
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", 
                "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress");
                SPTrustedClaimTypeInformation titleClaim = new SPTrustedClaimTypeInformation("Title", 
                "http://schemas.wingtip.com/sharepoint/2009/08/claims/title", 
                "http://schemas.wingtip.com/sharepoint/2009/08/claims/title");
    
                titleClaim.AcceptOnlyKnownClaimValues = true;
    
                idClaim.AddKnownClaimValue("user1@wingtip.com");
                idClaim.AddKnownClaimValue("user2@wingtip.com");
                idClaim.AddKnownClaimValue("user3@wingtip.com");
    
                titleClaim.AddKnownClaimValue("Engineer");
                titleClaim.AddKnownClaimValue("Manager");
                titleClaim.AddKnownClaimValue("CEO");
    
                // Create the string[] for all claims. This is required for 
                // the construction of the SPTrustedLoginProvider object.
                strClaimMapping.Add(idClaim.InputClaimType);
                strClaimMapping.Add(titleClaim.InputClaimType);
    
    
                X509Certificate2 ImportTrustCertificate = 
                new X509Certificate2(@"C:\StudentFiles\LabFiles\Module_6\Resources\STSTestCertPub.cer");
    
                claimMapping.Add(idClaim);
                claimMapping.Add(titleClaim);
    
                SPSecurityTokenServiceManager manager = SPSecurityTokenServiceManager.Local;
                SPTrustedLoginProvider provider = new SPTrustedLoginProvider(manager, 
                "WingtipSTS","WingtipSTS",new Uri("http://localhost:48924/WingtipSTS/default.aspx"),
                "https://intranet.contoso.com/_trust/", strClaimMapping.ToArray(),idClaim);  
    
                foreach (SPTrustedClaimTypeInformation claimTypeInfo in claimMapping)
                {
                    if (claimTypeInfo.InputClaimType == provider.IdentityClaimTypeInformation.InputClaimType)
                    {
                        continue;
                    }
                    provider.AddClaimTypeInformation(claimTypeInfo);
                }
    
                if (ImportTrustCertificate != null)
                {
                    provider.SigningCertificate = ImportTrustCertificate;
                }
    
    
                //provider.ClaimProviderName = "ContosoCRMClaimProvider";
    
                provider.UseWReplyParameter = true;
    
                manager.TrustedLoginProviders.Add(provider);
                manager.Update();
            }
    
  12. Build the RegisterSTS project, and then run it.

  13. Click the button to register the trusted login provider to the farm.

  1. Browse to the SharePoint 2010 Central Administration page.

  2. In the Application Management section, click Manage web applications.

  3. On the ribbon, click New.

  4. In the Create New Web Application dialog box, under Authentication, click Claims Based Authentication.

  5. In the IIS Web Site section, under Create a new IIS web site, change the Name field to SharePoint – Trusted.

  6. Change the Port number to 443.

  7. In the Security Configuration section, under Use Security Socket layer (SSL), click Yes, as shown in Figure 14.

  8. In the Claims Authentication Types section, do the following:

    1. Click Enable Windows Authentication.

    2. Click Integrated Windows Authentication.

    3. Click NTLM from the drop-down list.

    4. Click Trusted Identity Provider.

    5. Click WingtipSTS.

    Figure 14. Create New Web Application dialog box

    Create New Web Application dialog box
  9. Under Application Pool, select the existing AppPool : SharePointAppPool.

  10. In the Database Name and Authentication section, change the database name to WSS_Content_443. Leave other settings as their defaults.

  11. Click OK to create the web application.

  12. After the SSL web application is created, click Application Management, and then click Create site collection.

  13. Change the web application to https://intranet.contoso.com.

  14. For the title, type Trusted.

  15. Click Browse on the Primary Site Collection Administrator.

  16. On the People Picker, under WingtipSTS, do the following:

    Note Note

    As mentioned earlier, the WingtipSTS Claim Provider is a type of SPTrustedClaimProvder. It is generated automatically by SharePoint when registering the SPTrustedLoginProvider.

    1. Select EmailAddress. It shows that there are three available choices, as shown in Figure 15.

    2. Select user1@wingtip.com, and then click OK.

    Figure 15. People Picker

    People Picker
  17. Click OK to create the site collection.

Important note Important

Before you run this test, ensure that you have the WingtipSTS project up and running. You can either right-click the WingtipSTS project and then click View in Browser, or you can deploy it to an Internet Information Services (IIS) website.

  1. Navigate to https://intranet.contoso.com.

  2. In the Multiple Authentication Selector drop-down list, click WingtipSTS, as shown in Figure 16.

    Figure 16. Selecting WingtipSTS from the drop-down list

    Selecting WingtipSTS from the drop-down list

    You are redirected to the logon page of the WingtipSTS website, as shown in Figure 17.

    Figure 17. Logon page of the WingtipSTS website

    Logon page of the WingtipSTS website
  3. Type the credential for site administrator, which is user1@wingtip.com.

  4. After authentication, you are redirected back to the SharePoint site, as shown in Figure 18.

    Figure 18. Redirected back to the SharePoint site after authentication

    Redirected to SharePoint site after authentication
  5. Deploy a Web Part that you created and add it to the home page. Observe and make a note of what claims are added to the user.

  6. On the Site Actions menu, click Site Settings, and then click Users and Groups. Click user1@wingtip.com, and then look for the account name. Note the answer to the following questions:

    • What are the ClaimTypes for user1@wingtip.com?

    • What is the account name for user1@wingtip.com?

    • What does each character in the account name mean? (Decode the account name manually or by using code.)

  7. On the ribbon, under Site Actions, select Site Permissions, and then click Grant Permissions. Click the Browse icon to open the People Picker dialog box.

  8. Under WingtipSTS, click Title.

  9. Type Manager, and then click Search.

  10. From the search result, double-click Manager to add the "Manager" to the users list, and then click Add, as shown in Figure 19.

    Figure 19. People Picker displaying WingtipSTS employee titles

    People Picker displays WingtipSTS employee titles
  11. Close all Internet Explorer instances to clean up the claims authentication session cookie.

  12. Open a new instance of Internet Explorer and navigate to https://intranet.contoso.com.

  13. Try to log on as user2@wingtip.com. Are you able to log on? What if you use user3@wingtip.com?

In this walkthrough, you learn how to create a custom security token service (STS) and then set up the trust relationship between a SharePoint farm and the custom STS. The custom STS serves as the authentication provider. When users log on to the SharePoint site, they are first redirected to the logon page of the custom STS, and then they are redirected back to SharePoint after the authentication.

Show:
© 2014 Microsoft