How to: Use Protocol Transition for Impersonating and Delegating the Original Caller in WCF

patterns & practices Developer Center

Applies To

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

Summary

This how-to article walks you through the process of using protocol transition for impersonating and delegating the original caller. You will learn how to use the client certificate for authentication. You will then use the service for user (S4U) Kerberos extensions to create a Windows identity for the authenticated user, by using the user principal name (UPN) and impersonating and delegating the original caller.

Contents

  • Objectives
  • Overview
  • Summary of Steps
  • Step 1: Create a Sample WCF Service
  • Step 2: Configure wsHttpBinding with Certificate Authentication and Message Security
  • Step 3: Create and Install a Service Certificate
  • Step 4: Configure the Service Certificate for the WCF Service
  • Step 5: Impersonate the Original Caller in the WCF Service
  • Step 6: Configure the WCF Service Identity for Protocol Transition and Constrained Delegation
  • Step 7: Create a Test Client
  • Step 8: Add a WCF Service Reference to the Client
  • Step 9: Create and Install the Client Certificate for Authentication
  • Step 10: Configure the Client Certificate in the WCF Client Application
  • Step 11: Test the Client and WCF Service
  • Additional Resources

Objectives

  • Learn how to do protocol transition in WCF by using a client certificate.
  • Learn how to configure the WCF process identity for protocol transition and constrained delegation.

Overview

In many situations—for example, if your users access a WCF service over the Internet—you cannot use Kerberos authentication because firewalls prevent the client computer from directly communicating with the domain controller. Instead, your application must authenticate the client by using another approach, such as username authentication, or client certificate authentication.

Windows Server 2003 includes a protocol transition feature that permits services to use a non-Windows authentication mechanism to authenticate users, while still using Kerberos authentication and delegation to access downstream network resources. This allows your application to access downstream servers that require Windows authentication, and allows you to use Windows auditing to track user access to back-end resources.

Note that impersonating a Windows identity to access downstream resources brings a number of advantages, but also some disadvantages. The advantages include the ability to use Windows auditing to track user access to back-end resources, and the ability to implement fine-grained access controls to resources (such as databases) on a per-user basis. The disadvantages include the additional administration required to administer fine-grained access controls, and reduced scalability. For many applications, the trusted subsystem model is appropriate; for example, where the WCF service authenticates the caller, but then uses a service identity to access downstream resources on behalf of the original caller. This results in reduced administration and improved scalability.

The use of protocol transition to access downstream resources relies on two extensions to the Kerberos protocol. Both extensions are implemented in Windows Server 2003. These extensions are:

  • Service-for-User-to-Self (S4U2Self), which allows you to obtain a Windows token for the client by supplying a UPN without a password.
  • Service-for-User-to-Proxy (S4U2Proxy), which allows an administrator to control exactly which downstream services can be accessed with the S4U2Self token.

Summary of Steps

  • Step 1: Create a Sample WCF Service
  • Step 2: Configure wsHttpBinding with Certificate Authentication and Message Security
  • Step 3: Create and Install a Service Certificate
  • Step 4: Configure the Service Certificate for the WCF Service
  • Step 5: Impersonate the Original Caller in the WCF Service
  • Step 6: Configure the WCF Service Identity for Protocol Transition and Delegation
  • Step 7: Create a Test Client
  • Step 8: Add a WCF Service Reference to the Client
  • Step 9: Create and Install the Client Certificate for Authentication
  • Step 10: Configure the Client Certificate in the WCF Client Application
  • Step 11: Test the Client and WCF Service

Step 1: Create a Sample WCF Service

In this step, you create a WCF service in Visual Studio.

  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/WCFTestService).

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

  4. Browse to your WCF service (i.e., https://localhost/WCFTestService/Service.svc).

    You should see details of your WCF service.

Step 2: Configure wsHttpBinding with Certificate Authentication and Message Security

In this step, you configure the WCF service to use certificate authentication and message security.

  1. Right-click the Web.config file of the WCF service, and then click Edit WCF Configuration.

  2. In the Configuration Editor, in the Configuration section, expand Service and then expand Endpoints.

  3. Select the first node [Empty Name] and set the Name attribute to wsHttpEndpoint.

    By default, the name will be empty because it is an optional attribute.

  4. Click the Identity tab and then delete the Dns attribute value.

  5. In the Configuration Editor, select the Bindings folder.

  6. In the Bindings section, choose New Binding Configuration.

  7. In the Create a New Binding dialog box, select wsHttpBinding.

  8. Click OK.

  9. Set the Name of the binding configuration to some logical and recognizable name; for example, wsHttpEndpointBinding.

  10. Click the Security tab.

  11. Make sure that the Mode attribute is set to Message, which is the default setting.

  12. Set the MessageClientCredentialType to Certificate by selecting this option from the drop-down list.

  13. In the Configuration section, select the wsHttpEndpoint node.

  14. Set the BindingConfiguration attribute to wsHttpEndpointBinding by selecting this option from the drop-down list.

    This associates the binding configuration setting with the binding.

  15. In the Configuration Editor, on the File menu, click Save.

  16. In Visual Studio, open your configuration and comment out the identity element. It should look as follows:

          <!--<identity>
            <dns value="" />
          </identity>-->
    
  17. In Visual Studio, verify your configuration. The configuration should look as follows:

    …
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding">
          <security>
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="ServiceBehavior" name="Service">
        <endpoint address="" binding="wsHttpBinding"
          bindingConfiguration="wsHttpEndpointBinding"
          name="wsHttpEndpoint" contract="IService">
          <!--<identity>
            <dns value="" />
          </identity>-->
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
    …
    

Step 3: Create and Install a Service Certificate

In this step, you create a temporary service certificate and install it in the local store. This certificate will be used for service authentication and to encrypt the message, thereby protecting any other sensitive data.

Creating and installing the certificate is outside the scope of this How To article. For detailed steps on how to do this, see “How to: Create and Install Temporary Certificates in WCF for Message Security During Development.”

Note


If you are running on Microsoft Windows XP, give the certificate permissions for the ASPNET identity instead of the NT Authority\Network Service identity because the Internet Information Services (IIS) process runs under the ASPNET account in Windows XP.
The temporary certificate should be used for development and testing purposes only. For actual production deployment, you will need to get a valid certificate from a certificate authority (CA).

Step 4: Configure the Service Certificate for the WCF Service

In this step, you configure the WCF service to use the temporary certificate you created in the previous step.

  1. In the Configuration Editor, expand the Advanced node, and then expand the Service Behaviors and ServiceBehavior nodes.

  2. Click Add.

  3. In the Service Behavior Element Extensions dialog box, select the serviceCredentials option and then click Add.

  4. Expand the serviceCredentials node and then select the serviceCertificate node.

  5. Set the FindValue attribute to the name of the service certificate that you created; for example, "CN=tempCertServer".

  6. Leave the default settings for StoreLocation and StoreName.

  7. In the Configuration Editor, on the File menu, click Save.

  8. In Visual Studio, verify your configuration. The configuration should look as follows.

    ...
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
          <serviceCredentials>
            <serviceCertificate findValue="CN=tempCertServer" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    ...
    

Step 5: Impersonate the Original Caller in the WCF Service

Perform the following steps to retrieve the UPN from the client certificate, create the WindowsIdentity token, and impersonate the original caller.

  1. Add using statements to add references to the relevant namespaces as follows:

    using System.IdentityModel.Policy;
    using System.IdentityModel.Claims;
    using System.Security.Principal;
    
  2. Extract the Subject name from the certificate, as shown in the following example. Note that the Subject name for the client certificate is the user's UPN—this is done consciously at the time of client certificate creation in order to simplify the process. Alternatively, you could have other extended attributes with the user UPN.

    public string GetData(int value)
    {
    
       AuthorizationContext authCon = ServiceSecurityContext.Current.AuthorizationContext;
       X509CertificateClaimSet certClaims = null;
       foreach (ClaimSet cSet in authCon.ClaimSets)
       {
          certClaims = cSet as X509CertificateClaimSet;
          if (certClaims != null)
              break;
       }
       // As the subject name starts with "CN=" we are extracting the substring
       string userName = certClaims.X509Certificate.Subject.Substring(3);
    
       return string.Format("You entered: {0}", value);
    }
    
  3. Using the WindowsIdentity constructor, pass the UPN string as the parameter, get the WindowsIdentity token, and impersonate the original caller. If your WCF process identity is configured for protocol transition and trusted for delegation, you can access the remote resources as well.

    public string GetData(int value)
    {
    
       AuthorizationContext authCon = ServiceSecurityContext.Current.AuthorizationContext;
       X509CertificateClaimSet certClaims = null;
       foreach (ClaimSet cSet in authCon.ClaimSets)
       {
          certClaims = cSet as X509CertificateClaimSet;
          if (certClaims != null)
              break;
       }
       // As the subject name starts with "CN=" we are extracting the substring
       string userName = certClaims.X509Certificate.Subject.Substring(3);
    
       WindowsIdentity winId = new WindowsIdentity(userName);
       using (winId.Impersonate())
       {
           // access the local resources on behalf of the original callers
           // Or access remote resources, like SQL database on remote machine
           // if configured for protocol transition and constrained delegation.
       }
    
       return string.Format("You entered: {0}", value);
    }
    

Step 6: Configure the WCF Service Identity for Protocol Transition and Constrained Delegation

In this step, you configure Active Directory to allow your WCF service to use protocol transition and 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 a service principal name (SPN) for your custom domain account. Kerberos requires an SPN in order 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, select the option Use any authentication protocol.

  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 in order to support mutual authentication. To create an SPN for the domain account:

    1. Install the Windows Server 2003 Tools from the 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.
  1. On the domain controller, start the MMC Active Directory Users and Computers snap-in.

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

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

    This displays the user account properties.

  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, select the option Use any authentication protocol.

  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.

Step 7: Create a Test Client

In this step, you create a Windows Forms application 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.

Step 8: 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 (e.g., https://localhost/WCFTestService/Service.svc) and then click Go.

  3. In the Web reference name field, change ServiceReference1 to WCFTestService.

  4. Click Add Reference.

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

Step 9: Create and Install the Client Certificate for Authentication

In this step, you create a temporary client certificate by using the root CA created as part of the Step 3, and install it in the local store. This certificate will be used for client authentication and to encrypt the message, thereby protecting any other sensitive data.

  1. Copy the root CA certificate (RootCATest.cer) and private key file (RootCATest.pvk), created as part of Step 3, to the client machine.

  2. Open a Visual Studio command prompt and browse to the location where you copied the root CA certificate and private key file.

  3. Run following command for creating a certificate signed by the root CA certificate:

    makecert -sk MyKeyName -iv RootCATest.pvk -n "CN=User@DomainName.com" -ic RootCATest.cer -sr CurrentUser -ss my -sky signature -pe User1.cer
    
  4. In the Enter Private Key Password dialog box, enter the password for the root CA privatekeyfile created as part of Step 3 above, and then click OK.

For more information and detailed steps, see “How to: Create and Install Temporary Certificates in WCF for Message Security During Development.”

Step 10: Configure the Client Certificate in the WCF Client Application

In this step, you configure the WCF client to use the temporary certificate you created in the previous step.

  1. In your test client, right-click the App.config file and then click Edit WCF Configuration.

  2. In the Configuration Editor, expand the Advanced node, select Endpoint Behaviors, and then select New Endpoint Behavior Configuration.

  3. Click Add.

  4. In the Adding Behavior Element Extension Sections dialog box, select clientCredentials and then click Add.

  5. Expand the clientCredentials node, expand the serviceCertificate node, and then select authentication below this node.

  6. Set the CertificateValidationMode to PeerTrust by choosing this option from the drop-down list.

  7. Select the clientCertificate node, and then set the FindValue attribute to the subject name of the client certificate that you created and installed in Step 7; for example, "CN=User@DomainName.com".

  8. Leave the default StoreLocation attribute set to CurrentUser as is.

  9. In the Configuration Editor, expand the Client node, expand the Endpoints node, and then select the wsHttpEndpoint node.

  10. Set the BehaviorConfiguration attribute to NewBehavior by choosing this option from the drop-down list.

    This is the endpoint behavior you just created.

  11. In the Configuration Editor, on the File menu, click Save.

  12. In Visual Studio, verify your configuration. The configuration should look as follows.

    <system.serviceModel>
        <behaviors>
            <endpointBehaviors>
                <behavior name="NewBehavior">
                    <clientCredentials>
                        <clientCertificate findValue="CN=tempCertClient"/>
                    </clientCredentials>
                </behavior>
            </endpointBehaviors>
        </behaviors>
        ...
        <client>
            <endpoint address="http://<<service address>>"
                behaviorConfiguration="NewBehavior" binding="wsHttpBinding"
                bindingConfiguration="wsHttpEnpoint1" contract="ServiceReference1.IService"
                name="wsHttpEnpoint">
                <identity>
                    <certificate encodedValue="<<Encode Value>>" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
    

Step 11: Test the Client and WCF Service

In this step, you access the WCF service, pass the user credentials, and make sure that the username authentication works.

  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 operation 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, the message “You entered: 123” should appear.

Additional Resources