Delegation and Impersonation with WCF


Impersonation is a common technique that services use to restrict client access to a service domain's resources. Service domain resources can either be machine resources, such as local files (impersonation), or a resource on another machine, such as a file share (delegation). For a sample application, see Impersonating the Client. For an example of how to use impersonation, see How to: Impersonate a Client on a Service.

System_CAPS_ICON_important.jpg Important

Be aware that when impersonating a client on a service, the service runs with the client's credentials, which may have higher privileges than the server process.

Typically, clients call a service to have the service perform some action on the client’s behalf. Impersonation allows the service to act as the client while performing the action. Delegation allows a front-end service to forward the client’s request to a back-end service in such a way that the back-end service can also impersonate the client. Impersonation is most commonly used as a way of checking whether a client is authorized to perform a particular action, while delegation is a way of flowing impersonation capabilities, along with the client’s identity, to a back-end service. Delegation is a Windows domain feature that can be used when Kerberos-based authentication is performed. Delegation is distinct from identity flow and, because delegation transfers the ability to impersonate the client without possession of the client’s password, it is a much higher privileged operation than identity flow.

Both impersonation and delegation require that the client have a Windows identity. If a client does not possess a Windows identity, then the only option available is to flow the client’s identity to the second service.

Windows Communication Foundation (WCF) supports impersonation for a variety of client credentials. This topic describes service model support for impersonating the caller during the implementation of a service method. Also discussed are common deployment scenarios involving impersonation and SOAP security and WCF options in these scenarios.

This topic focuses on impersonation and delegation in WCF when using SOAP security. You can also use impersonation and delegation with WCF when using transport security, as described in Using Impersonation with Transport Security.

WCF SOAP security has two distinct methods for performing impersonation. The method used depends on the binding. One is impersonation from a Windows token obtained from the Security Support Provider Interface (SSPI) or Kerberos authentication, which is then cached on the service. The second is impersonation from a Windows token obtained from the Kerberos extensions, collectively called Service-for-User (S4U).

Cached Token Impersonation

You can perform cached-token impersonation with the following:

S4U-Based Impersonation

You can perform S4U-based impersonation with the following:

  • WSHttpBinding, WSDualHttpBinding, and NetTcpBinding with a certificate client credential that the service can map to a valid Windows account.

  • Any CustomBinding that uses a Windows client credential with the requireCancellation property set to false.

  • Any CustomBinding that uses a user name or Windows client credential and secure conversation with the requireCancellation property set to false.

The extent to which the service can impersonate the client depends on the privileges the service account holds when it attempts impersonation, the type of impersonation used, and possibly the extent of impersonation the client permits.

System_CAPS_ICON_note.jpg Note

When the client and service are running on the same computer and the client is running under a system account (for example, Local System or Network Service), the client cannot be impersonated when a secure session is established with stateful Security Context tokens. A Windows Form or console application typically runs under the currently logged-in account, so that account can be impersonated by default. However, when the client is an ASP.NET page and that page is hosted in IIS 6.0 or IIS 7.0, then the client does run under the Network Service account by default. All of the system-provided bindings that support secure sessions use a stateless security context token (SCT) by default. However, if the client is an ASP.NET page, and secure sessions with stateful SCTs are used, the client cannot be impersonated. For more information about using stateful SCTs in a secure session, see How to: Create a Security Context Token for a Secure Session.

Most impersonation scenarios involve executing the service method in the caller context. WCF provides an impersonation feature that makes this easy to do by allowing the user to specify the impersonation requirement in the OperationBehaviorAttribute attribute. For example, in the following code, the WCF infrastructure impersonates the caller before executing the Hello method. Any attempt to access native resources inside the Hello method succeed only if the access control list (ACL) of the resource allows the caller access privileges. To enable impersonation, set the Impersonation property to one of the ImpersonationOption enumeration values, either ImpersonationOption.Required or ImpersonationOption.Allowed, as shown in the following example.

System_CAPS_ICON_note.jpg Note

When a service has higher credentials than the remote client, the credentials of the service are used if the Impersonation property is set to Allowed. That is, if a low-privileged user provides its credentials, a higher-privileged service executes the method with the credentials of the service, and can use resources that the low-privileged user would otherwise not be able to use.

    public interface IHelloContract
        string Hello(string message);

    public class HelloService : IHelloService
        [OperationBehavior(Impersonation = ImpersonationOption.Required)]
        public string Hello(string message)
            return "hello";

The WCF infrastructure can impersonate the caller only if the caller is authenticated with credentials that can be mapped to a Windows user account. If the service is configured to authenticate using a credential that cannot be mapped to a Windows account, the service method is not executed.

System_CAPS_ICON_note.jpg Note

On Windows XP, impersonation fails if a stateful SCT is created, resulting in an InvalidOperationException. For more information, seeUnsupported Scenarios.

Sometimes a caller does not need to impersonate the entire service method to function, but for only a portion of it. In this case, obtain the Windows identity of the caller inside the service method and imperatively perform the impersonation. Do this by using the WindowsIdentity property of the ServiceSecurityContext to return an instance of the WindowsIdentity class and calling the Impersonate method before using the instance.

System_CAPS_ICON_note.jpg Note

Be sure to use the Visual BasicUsing statement or the C# using statement to automatically revert the impersonation action. If you do not use the statement, or if you use a programming language other than Visual Basic or C#, be sure to revert the impersonation level. Failure to do this can form the basis for denial of service and elevation of privilege attacks.

    public class HelloService : IHelloService
        public string Hello(string message)
            WindowsIdentity callerWindowsIdentity =
            if (callerWindowsIdentity == null)
                throw new InvalidOperationException
               ("The caller cannot be mapped to a WindowsIdentity");
            using (callerWindowsIdentity.Impersonate())
                // Access a file as the caller.
            return "Hello";

In some cases, you must perform all the methods of a service in the caller’s context. Instead of explicitly enabling this feature on a per-method basis, use the ServiceAuthorizationBehavior. As shown in the following code, set the ImpersonateCallerForAllOperations property to true. The ServiceAuthorizationBehavior is retrieved from the collections of behaviors of the ServiceHost class. Also note that the Impersonation property of the OperationBehaviorAttribute applied to each method must also be set to either Allowed or Required.

            // Code to create a ServiceHost not shown.
            ServiceAuthorizationBehavior MyServiceAuthoriationBehavior = 
            MyServiceAuthoriationBehavior.ImpersonateCallerForAllOperations = true;

The following table describes WCF behavior for all possible combinations of ImpersonationOption and ImpersonateCallerForAllServiceOperations.

Requiredn/aWCF impersonates the caller
AllowedfalseWCF does not impersonate the caller
AllowedtrueWCF impersonates the caller
NotAllowedfalseWCF does not impersonate the caller
NotAllowedtrueDisallowed. (An InvalidOperationException is thrown.)

In some scenarios the client has partial control over the level of impersonation the service performs when a Windows client credential is used. One scenario occurs when the client specifies an Anonymous impersonation level. The other occurs when performing impersonation with a cached token. This is done by setting the AllowedImpersonationLevel property of the WindowsClientCredential class, which is accessed as a property of the generic ChannelFactory<TChannel> class.

System_CAPS_ICON_note.jpg Note

Specifying an impersonation level of Anonymous causes the client to log on to the service anonymously. The service must therefore allow anonymous logons, regardless of whether impersonation is performed.

The client can specify the impersonation level as Anonymous, Identification, Impersonation, or Delegation. Only a token at the specified level is produced, as shown in the following code.

            ChannelFactory<IEcho> cf = new ChannelFactory<IEcho>("EchoEndpoint");
            cf.Credentials.Windows.AllowedImpersonationLevel  = 

The following table specifies the impersonation level the service obtains when impersonating from a cached token.

AllowedImpersonationLevel valueService has SeImpersonatePrivilegeService and client are capable of delegationCached token ImpersonationLevel

By passing the service its user name and password, a client enables WCF to log on as that user, which is equivalent to setting the AllowedImpersonationLevel property to Delegation. (The AllowedImpersonationLevel is available on the WindowsClientCredential and HttpDigestClientCredential classes.) The following table provides the impersonation level obtained when the service receives user name credentials.

AllowedImpersonationLevelService has SeImpersonatePrivilegeService and client are capable of delegationCached token ImpersonationLevel
Service has SeTcbPrivilegeService has SeImpersonatePrivilegeService and client are capable of delegationCached token ImpersonationLevel

It is possible for a client to authenticate itself to a service using a certificate, and to have the service map the client to an existing account through Active Directory. The following XML shows how to configure the service to map the certificate.

    <behavior name="MapToWindowsAccount">  
          <authentication mapClientCertificateToWindowsAccount="true" />  

The following code shows how to configure the service.

// Create a binding that sets a certificate as the client credential type.  
WSHttpBinding b = new WSHttpBinding();  
b.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;  
// Create a service host that maps the certificate to a Windows account.  
Uri httpUri = new Uri("http://localhost/Calculator");  
ServiceHost sh = new ServiceHost(typeof(HelloService), httpUri);  
sh.Credentials.ClientCertificate.Authentication.MapClientCertificateToWindowsAccount = true;  

To delegate to a back-end service, a service must perform Kerberos multi-leg (SSPI without NTLM fallback) or Kerberos direct authentication to the back-end service using the client’s Windows identity. To delegate to a back-end service, create a ChannelFactory<TChannel> and a channel, and then communicate through the channel while impersonating the client. With this form of delegation, the distance at which the back-end service can be located from the front-end service depends on the impersonation level achieved by the front-end service. When the impersonation level is Impersonation, the front-end and back-end services must be running on the same machine. When the impersonation level is Delegation, the front-end and back-end services can be on separate machines or on the same machine. Enabling delegation-level impersonation requires that Windows domain policy be configured to permit delegation. For more information about configuring Active Directory for delegation support, see Enabling Delegated Authentication.

System_CAPS_ICON_note.jpg Note

When a client authenticates to the front-end service using a user name and password that correspond to a Windows account on the back-end service, the front-end service can authenticate to the back-end service by reusing the client’s user name and password. This is a particularly powerful form of identity flow, because passing user name and password to the back-end service enables the back-end service to perform impersonation, but it does not constitute delegation because Kerberos is not used. Active Directory controls on delegation do not apply to user name and password authentication.

Delegation Ability as a Function of Impersonation Level

Impersonation levelService can perform cross-process delegationService can perform cross-machine delegation

The following code example demonstrates how to use delegation.

    public class HelloService : IHelloService
        [OperationBehavior(Impersonation = ImpersonationOption.Required)]
        public string Hello(string message)
            WindowsIdentity callerWindowsIdentity = ServiceSecurityContext.Current.WindowsIdentity;
            if (callerWindowsIdentity == null)
                throw new InvalidOperationException
                 ("The caller cannot be mapped to a Windows identity.");
            using (callerWindowsIdentity.Impersonate())
                EndpointAddress backendServiceAddress = new EndpointAddress("http://localhost:8000/ChannelApp");
                // Any binding that performs Windows authentication of the client can be used.
                ChannelFactory<IHelloService> channelFactory = new ChannelFactory<IHelloService>(new NetTcpBinding(), backendServiceAddress);
                IHelloService channel = channelFactory.CreateChannel();
                return channel.Hello(message);

How to Configure an Application to Use Constrained Delegation

Before you can use constrained delegation, the sender, receiver, and the domain controller must be configured to do so. The following procedure lists the steps that enable constrained delegation. For details about the differences between delegation and constrained delegation, see the portion of Windows Server 2003 Kerberos Extensions that discusses constrained discussion.

  1. On the domain controller, clear the Account is sensitive and cannot be delegated check box for the account under which the client application is running.

  2. On the domain controller, select the Account is trusted for delegation check box for the account under which the client application is running.

  3. On the domain controller, configure the middle tier computer so that it is trusted for delegation, by clicking the Trust computer for delegation option.

  4. On the domain controller, configure the middle tier computer to use constrained delegation, by clicking the Trust this computer for delegation to specified services only option.

For more detailed instructions about configuring constrained delegation, see the following topics on MSDN:

Using Impersonation with Transport Security
Impersonating the Client
How to: Impersonate a Client on a Service
ServiceModel Metadata Utility Tool (Svcutil.exe)