How to: Use Delegation for Flowing the Original Caller Credentials to the Back End in WCF Calling from Windows Forms

patterns & practices Developer Center

Applies To

  • Microsoft Windows Communication Foundation (WCF) 3.5
  • Microsoft Visual Studio 2008

Summary

This How To article shows you how to flow the original caller credentials to the back end in a WCF service that has been called from a Windows Forms application. The article shows you how to configure the WCF service, implement delegation, and test the service with a sample Windows Forms client.

Contents

  • Objectives
  • Overview
  • Summary of Steps
  • Step 1: Create a Sample WCF Service
  • Step 2: Configure the WCF Service to Use Windows Authentication
  • Step 3: Identify and Configure the Remote Service to Be Accessed
  • Step 4: Configure the WCF Service Identity Trusted for Constrained Delegation
  • Step 5: Impersonate the Original Caller in the WCF Service
  • Step 6: Create a Test Client Application
  • Step 7: Add a WCF Service Reference to the Client
  • Step 8: Test the Client and WCF Service
  • Additional Resources

Objectives

  • Learn how to configure a WCF process identity trusted for delegation.
  • Learn how to constrain the delegation.
  • Learn how to impersonate the original caller.

Overview

When a WCF service impersonates the original caller, it accesses resources by using the security context of the authenticated user. However, the application can only access local resources. To access network resources while impersonating an original caller, your service must use delegation. If your service uses Kerberos authentication to authenticate its users, you can use delegation to pass the caller's identity through the layers of your application, and to access network resources.

Note

If your application does not use Kerberos authentication, you can use protocol transition to switch from a non-Kerberos authentication mechanism to Kerberos, and then use delegation to pass on the identity.

Kerberos delegation by default is unconstrained, and servers that are configured as trusted for delegation in Microsoft Active Directory can access any network resources or any machine on the network while using the impersonated user's security context. This represents a potential security threat, particularly if the Web server is compromised.

To address this issue, you should use constrained delegation. This allows administrators to specify exactly which services on a downstream server or a domain account can be accessed when using an impersonated user's security context.

Note

The list of services that can be accessed by delegation is maintained in an Active Directory list referred to as the A2D2 list.

Summary of Steps

  • Step 1: Create a Sample WCF Service
  • Step 2: Configure the WCF Service to Use Windows Authentication
  • Step 3: Identify and Configure the Remote Service to Be Accessed
  • Step 4: Configure the WCF Service Identity Trusted for Constrained Delegation
  • Step 5: Impersonate the Original Caller in the WCF Service
  • Step 6: Create a Test Client Application
  • Step 7: Add a WCF Service Reference to the Client
  • Step 8: Test the Client and WCF Service

Step 1: Create a Sample WCF Service

In this step, you create a sample WCF service in Visual Studio, hosted in an Internet Information Services (IIS) virtual directory.

  1. In Visual Studio, on the File menu, click New Web Site.

  2. In the Templates section, select WCF Service. Make sure that the Location is set to Http and specify the virtual directory to be created in the Path (e.g., https://localhost/WCFServiceDelegation).

  3. In the New Web Site dialog box, click OK to create a virtual directory, a solution file, and a sample WCF service for the solution.

  4. In Microsoft Internet Explorer, browse to your WCF service at https://localhost/WCFServiceDelegation/Service.svc.

    You should see details of your WCF service in the browser.

Step 2: Configure the WCF Service to Use Windows Authentication

By default, Visual Studio configures your WCF service to use wsHttpBinding with Windows authentication and message security.

  • In Visual Studio, verify your configuration settings in Web.config. The configuration should look as follows:

    ...
    <services>
      <service name="Service" behaviorConfiguration="ServiceBehavior">
        <endpoint address="" binding="wsHttpBinding" contract="IService">
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding"
             contract="IMetadataExchange"/>
      </service>
    </services>
    ...
    

Step 3: Identify and Configure the Remote Service to Be Accessed

In this step, you identify the remote service to be accessed on behalf of the original caller. This service needs to be enabled for Windows authentication and configured with access rights to the original caller.

For the purposes of this exercise, you will access the Microsoft SQL Server® database on a remote server on behalf of the original caller.

  1. If you use a custom domain account to run SQL Server, you must create a service principal name (SPN) for this account. You can do this by using the following command:

    setspn -A MSSQLSvc/ databaseservername.fullyqualifieddomainname
    domain\customAccountName 
    

    If you run SQL Server by using the System account (which is not recommended because of the associated high privileges that an attacker could exploit), an SPN is created automatically for you.

  2. To allow access to SQL Server, you must create a SQL Server login for each of your application's end users or for a set of groups that the users belong to, and grant them read access to the target database.

Step 4: Configure the WCF Service Identity Trusted for Constrained Delegation

In this step, you configure Active Directory to allow your WCF service to use constrained delegation to access a remote database server.

If your WCF service runs using the Network Service machine account, you must enable constrained delegation for your WCF server computer. However, if your WCF service runs under a custom domain account, you must enable constrained delegation for the custom domain account.

Note

If you use a custom domain account for running your WCF service, create an SPN for your custom domain account. Kerberos requires an SPN to support mutual authentication.

To configure constrained delegation for the machine account

This procedure assumes that you are running your WCF service under the Network Service machine account.

  1. On the domain controller, start the Microsoft Management Console (MMC) Active Directory Users and Computers snap-in.

  2. In the left pane of the MMC snap-in, click the Computers node.

  3. In the right pane, double-click your WCF server computer to display the Properties dialog box.

  4. On the Delegation tab of the Properties window for the WCF server computer, Do not trust the computer for delegation is selected by default. To use constrained delegation, select Trust this computer for delegation to specified services only. You specify precisely which service or services can be accessed in the bottom pane.

  5. Beneath Trust this computer for delegation to specified services only, keep the default option Use Kerberos only selected.

  6. Click the Add button to display the Add Services dialog box.

  7. Click the Users or computers button.

  8. In the Select Users or Computers dialog box, type the name of your database server computer if you are running SQL Server as System or Network Service.

    Alternatively, if you are running SQL Server by using a custom domain account, enter that account name instead and then click OK.

  9. You will see all the SPNs configured for the selected user or computer account. To restrict access to SQL Server, select the MSSQLSvc service, and then click OK.

Note

If you want to delegate to a file on a file share, you need to select the Common Internet File System (CIFS) service.

To configure constrained delegation for a custom domain account

This procedure assumes that you are running your Web application under a custom domain account.

  1. Create an SPN for your custom domain account. Kerberos requires an SPN to support mutual authentication. To create an SPN for the domain account:

    1. Install the Windows Server 2003 Tools from the Microsoft Windows Server 2003 CD.

    2. From a command prompt, run the Setspn tool twice from the C:\Program Files\Support Tools directory as shown below:

      setspn -A HTTP/wcfservername domain\customAccountName

      setspn -A HTTP/wcfservername.fullyqualifieddomainname

      domain\customAccountName

      Note

      You can only have a single SPN associated with any HTTP service (DNS) name, which means you cannot create SPNs for different service accounts mapped to the same HTTP server unless they are on different ports. The SPN can include a port number.

  2. On the domain controller, start the MMC Active Directory Users and Computers snap-in.

  3. In the left pane of the MMC snap in, click the Users node.

  4. In the right pane, double-click the user account you are using to run the WCF service.

    This displays the user account properties.

  5. On the Delegation tab of the Properties window for the WCF server computer, Do not trust the computer for delegation is selected by default. To use constrained delegation, select Trust this computer for delegation to specified services only. You specify precisely which service or services can be accessed in the bottom pane.

  6. Beneath Trust this computer for delegation to specified services only, keep the default option Use Kerberos only selected.

  7. Click the Add button to display the Add Services dialog box.

  8. Click the Users or computers button.

  9. In the Select Users or Computers dialog box, type the name of your database server computer if you are running SQL Server as System or Network Service.

    Alternatively, if you are running SQL Server by using a custom domain account, enter that account name instead and then click OK.

  10. You will see all the SPNs configured for the selected user or computer account. To restrict access to SQL Server, select the MSSQLSvc service, and then click OK.

Step 5: Impersonate the Original Caller in the WCF Service

Perform the following steps to declaratively impersonate specific operations:

  1. In the Solution Explorer, expand the App_Code folder under your WCF Service project, and then open the Service.cs file.

  2. Add a using statement for the System.Security.Principal namespace.

  3. Set the impersonation required on the operation implementation of the specific operation as follows:

    [OperationBehavior(Impersonation = ImpersonationOption.Required)]
    public string GetData(int value)
    {
      return string.Format("Hi, {0}, you have entered: {1}",
                               WindowsIdentity.GetCurrent().Name, value);
    }
    
  4. Add the database access code to the WCF Service operation implementation. The remote database is accessed using the original caller's security context.

    public string GetData(int value)
    {
       // Access the database 
        using (SqlConnection conn = new SqlConnection())
        {
          conn.ConnectionString = "Connection String";
          conn.Open();
          SqlCommand cmd = new SqlCommand("Select * from <<tableName>>",
                                           conn); 
          SqlDataAdapter da = new SqlDataAdapter(cmd);
          da.Fill(dt);
        }
    
       return string.Format("Hi, {0}, you have entered: {1}",
                               WindowsIdentity.GetCurrent().Name, value);
    }
    

Step 6: Create a Test Client Application

In this step, you create a Windows Forms application that you will use to test the WCF service.

  1. Right-click your solution, click Add, and then click New Project.
  2. In the Add New Project dialog box, in the Templates section, select Windows Forms Application.
  3. In the Name field, type Test Client and then click OK to create a Windows Forms application for testing.

Step 7: Add a WCF Service Reference to the Client

In this step, you add a reference to your WCF service.

  1. Right-click your client project and then click Add Service Reference.

  2. In the Add Service Reference dialog box, set the URL to your WCF service: https://localhost/WCFServiceDelegation/Service.svc

  3. In the Namespace field, change ServiceReference1 to WCFTestService.

  4. Click OK.

    A reference to WCFTestService should appear beneath Service References in your client project.

Step 8: Test the Client and WCF Service

In this step, you access the WCF service and make sure that it impersonates as expected.

  1. In your client project, drag a button control onto your form.

  2. Double-click the button control to show the underlying code.

  3. Create an instance of the proxy and call the GetData method of your WCF service. The code should look as follows:

    private void button1_Click(object sender, EventArgs e)
    {
          WCFTestService.ServiceClient myService = new
                                WCFTestService.ServiceClient();
          MessageBox.Show(myService.GetData(123));
          myService.Close();
    }
    
  4. Right-click the client project and then click Set as Startup Project.

  5. Run the client application by pressing F5 or CTRL+F5. When you click the button on the form, it should display the message “Hi, <<logged in user id>>, you have entered: 123”.

Additional Resources