Impersonation/Delegation

patterns & practices Developer Center

How to: Choose Between a Trusted Subsystem and Impersonation/Delegation

With the trusted subsystem model, you use your WCF service's process identity to access downstream network resources such as databases. With impersonation/delegation, you use impersonation and use the original caller's identity to access the database.

A trusted subsystem offers better scalability because your application benefits from efficient connection pooling. You also minimize back-end ACL management. Only the trusted identity can access the database—your end users have no direct access. In the trusted subsystem model, the WCF service is granted broad access to back-end resources. As a result, a compromised WCF service could potentially make it easier for an attacker to gain broad access to back-end resources. Keeping the service account's credentials protected is essential.

With impersonation/delegation, you benefit from operating system auditing because you can track which users have attempted to access specific resources. You can also enforce granular access controls in the database, and individual user accounts can be restricted independently of one another in the database.

Additional Resources

How to: Impersonate the Original Caller When Using Windows Authentication

When using Windows authentication, you have access to original callers' Windows identities. You can impersonate the original caller whenever downstream code needs to authorize based on the original caller's identity. For instance, you may have authorization checks in business logic called by WCF, or you may want to access resources that have access control lists (ACLs) allowing specific user access.

You can impersonate the original caller either declaratively or programmatically, depending on the following circumstances:

  • Impersonate the original caller declaratively when you want to access Microsoft Windows resources that are protected with ACLs configured for your application's domain user accounts.
  • Impersonate the original caller programmatically when you want to access resources predominantly by using the application's process identity, but specific sections of the operation need to use the original caller's identity.

Additional Resources

How to: Impersonate Programmatically in WCF

Programmatic impersonation allows you to impersonate on specific lines of code rather than the entire operation. This fine-grained approach to impersonation can reduce security risks; however, be aware that it is easier to make a mistake during implementation that could leave your code impersonating at higher privilege in the event of an error. Use the using statement to revert impersonation automatically.

To impersonate the original caller programmatically, you need to have access to the Windows identity of the original caller, calling into your WCF service. For this, you need to configure your WCF service to require Windows authentication.

Use the Impersonate method of the ServiceSecurityContext.Current.WindowsIdentity class as follows:


public string GetData(int value)
{
 using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
 {
     // Execute under security context of the original caller
 }   
}

Ff647465.note(en-us,PandP.10).gifNote:
Important: Revert the impersonation when you are done; in the above example, the using statement does this for you.

Additional Resources

How to: Impersonate Declaratively In WCF

Use the OperationBehavior attribute to impersonate declaratively. There are two options for declarative impersonation:

  • Impersonating on specific operations
  • Impersonating on the entire service

Impersonating on Specific Operations

Use this option when you want to impersonate the original caller for the entire duration of a specific operation. You can impersonate declaratively by applying the OperationBehaviorAttribute attribute on any operation that requires client impersonation, as shown in the following code example:


[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetData(int value)
{
   return “test”;
}

Impersonating on the Entire Service

Use this option when you want to impersonate the original caller for the entire duration of all the operations. To impersonate the entire service, set the impersonateCallerForAllOperations attribute to "true" in the WCF configuration file, as shown in the following example:


…
<behaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <serviceAuthorization impersonateCallerForAllOperations="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>
…

When impersonating for all operations, the Impersonation property of the OperationBehaviorAttribute attribute applied to each method must also be set to either Allowed or Required.

Additional Resources

How to: Delegate the Original Caller to Call Back-end Services When Using Windows Authentication

Use delegation for flowing the impersonated original user's security context (Windows identity) to the remote back-end service. On the remote back-end service, the original user's Windows identity can be used to authenticate or impersonate the original caller, in order to restrict or authorize the original caller's access to local resources.

Perform the following steps to delegate the original caller to back-end resources:

  1. Configure the WCF process identity to be trusted for delegation. On Windows Server 2003 or later, use constrained delegation. This allows administrators to specify exactly which services can be accessed on a downstream server or a domain account.
  2. Impersonate the original caller by using either programmatic or declarative impersonation when accessing the downstream resources.

Additional Resources

How to: Impersonate the Original Caller Without Windows Authentication

When using non-Windows authentication such as certificate or username authentication, if you need to impersonate the original caller (if the caller has a Windows account) or a service account, you have the following two options:

  • Using the service for user (S4U) Kerberos extensions. To use this option, you must grant your process account the “Act as part of the operating system” user right.
  • Using the LogonUser Windows API. This needs to have access to the user credentials (username and password), which increases the security risk of maintaining the user credentials in the WCF service.
Ff647465.note(en-us,PandP.10).gifNote:
S4U Kerberos extensions place your process within the trusted computing base (TCB) of the Web server, which makes your Web server process very highly privileged. Where possible, you should avoid this approach because an attacker who manages to inject code and compromise your Web application will have unrestricted capabilities on the local computer.

Additional Resources

How to: Impersonate the Original Caller Using S4U Kerberos Extensions

Perform the following steps to impersonate the original caller using S4U Kerberos extensions:

  1. Grant your WCF process account the Act as part of the operating system user right. If you are running using the network service account, the account has this right by default.
  2. Get the user name for the original caller and create a user principal name (UPN) for the user in a format similar to the following:

    username@FullyQualifiedDomainName.com

  3. Using the WindowsIdentity constructor, pass the UPN string as the parameter, get the WindowsIdentity token, and impersonate the original caller as follows:
    
    String username = “username@FullyQualifiedDomainName.com”;
    WindowsIdentity winId = new WindowsIdentity(userName);
    using (winId.Impersonate())
    {
      // access the local resources on behalf of the original callers       
    }
    
    
  4. Make sure to revert the impersonation; in the above example, the using statement does this for you automatically.

Additional Resources

How to: Delegate the Original Caller Using S4U Kerberos Extensions

Perform the following steps to delegate the original caller using S4U Kerberos extensions:

  1. Grant your WCF process account the Act as part of the operating system user right. If you are running using the network service account, the account has this right by default.
  2. Configure the WCF Process Identity with “Trust this computer for delegation to your specified services only,” by selecting the Use any authentication protocol option.
  3. Get the username for the original caller and create a UPN for the user in a format similar to the following:

    username@FullyQualifiedDomainName.com

  4. Using the WindowsIdentity constructor, pass the UPN string as the parameter, get the WindowsIdentity token, and impersonate the original caller as follows:
    
     String username = “username@FullyQualifiedDomainName.com”;
     WindowsIdentity winId = new WindowsIdentity(userName);
     using (winId.Impersonate())
     {
      // access the remote resources on behalf of the original caller       
     }
    
    
  5. Make sure to revert the impersonation; in the above example, the using statement does this for you automatically.

Additional Resources

How to: Impersonate and Delegate Using the LogonUser Windows API

You can use the Microsoft Win32 LogonUser() API (via P/Invoke) to create impersonation tokens, but only when your WCF service is not trusted for delegation, because this option forces you to store usernames and passwords on your WCF service.

The following code example shows how the LogonUser API is used for impersonation:


using System.Runtime.InteropServices;
…
// Declare the logon types as constants
const long LOGON32_LOGON_NETWORK = 3;

// Declare the logon providers as constants
const long LOGON32_PROVIDER_DEFAULT = 0;

[DllImport("advapi32.dll",EntryPoint = "LogonUser")]
private static extern bool LogonUser(
           string lpszUsername,
           string lpszDomain,
           string lpszPassword,
           int dwLogonType,
           int dwLogonProvider,
           ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);

private void ImpersonateAndUse(string Username,
                                        string Password,
                                        string Domain)
{
  IntPtr token = new IntPtr(0);
  token = IntPtr.Zero;
  // Call LogonUser to obtain a handle to an access token.
  bool returnValue = LogonUser(Username, Domain,Password,
                                 (int)LOGON32_LOGON_NETWORK,
                                 (int)LOGON32_PROVIDER_DEFAULT,
                                 ref token);
  if (false == returnValue)
  {
     int ret = Marshal.GetLastWin32Error();
     string strErr = String.Format("LogonUser failed with error code : {0}", ret);
     throw new ApplicationException(strErr, null);
  }
  WindowsIdentity newId = new WindowsIdentity(token);
  WindowsImpersonationContext impersonatedUser = newId.Impersonate();
  try
  {
     // do the operations using original user security context
  }
  finally
  {
     // stop impersonating
     impersonatedUser.Undo();
     CloseHandle(token);
  }
}

Additional Resources

How to: Flow the Original Caller from an ASP.NET Client to WCF

Perform the following steps to impersonate the original caller from an ASP.NET client to a WCF service:

  1. Configure your WCF service to use Windows authentication.
  2. Configure the ASP.NET application's process identity for constrained delegation to the WCF service.
  3. Impersonate the original caller in ASP.NET when calling the WCF service, as follows:
    
    using System.Security.Principal;
    …
    protected void Button1_Click(object sender, EventArgs e)
    {
        // Obtain the authenticated user's Identity and impersonate the original caller
        using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
        {
            WCFTestService.ServiceClient myService = new WCFTestService.ServiceClient();
            Response.Write(myService.GetData(123) + "<br/>");
            myService.Close();
        }
    }
    …
    
    

Additional Resources

How to: Control Access to a Remote Resource Based on the Original Caller's Identity

Use delegation to flow the impersonated original user's security context (Windows identity) to the remote back-end service. On the remote back-end service, the original user's Windows identity can be used to authenticate or impersonate the original caller, in order to restrict or authorize the original caller's access to local resources.

When using delegation, on Windows Server 2003 or later, 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.

Additional Resources

Show: