Foundations

Code Access Security in WCF, Part 1

Juval Lowy

Code download available at:Foundations2008_04.exe(479 KB)

Contents

CAS at a Glance
Client-Side CAS
Partially Trusted Clients
Client-Side Demands
Raw WCF Demands
Structured Demands with PartialTrustClientBase<T>
Analyzing the Demands of Invoke
Implementing Client-Side Structured Demands

Introduced in the Microsoft® .NET Framework 1.0, code access security (CAS) is probably the single differentiating capability of .NET compared with unmanaged code. CAS is built into the very fabric of the .NET Framework, affecting every operation in managed code, something that unmanaged code can never achieve.

The first release of Windows® Communication Foundation (WCF) offered no support for CAS; the System.ServiceModel assembly did not allow any partially trusted callers, which disabled CAS support. The second release introduced rudimentary support for CAS in some of the HTTP bindings and only for a limited set of scenarios. This change enabled me to write a small framework that provides comprehensive support for CAS without compromising either the WCF programming model or CAS.

In this first installment of two columns on CAS, I will briefly discuss code access security in WCF, and then proceed to show my solution for enabling partially trusted clients of WCF services.

CAS at a Glance

The .NET Framework defines 24 different security permissions, governing almost any type of operation. There are permissions for file I/O, UI, reflection, security, network, data access, and so on. A permission type can be applied to a specific resource, such as permission to read from a specific file in the case of the file I/O permission or permission to display specific types of windows as with the UI permission. It may also be completely denied (such as no file I/O operations at all) or completely granted (such as unrestricted file I/O access).

Permissions are grouped into permission sets and every assembly is assigned a set. The .NET Framework defines some standard permission sets such as FullTrust (implies all permissions) or Execution (permission to only access the CPU). Administrators can use the .NET Configuration tool to define custom permission sets, and developers can define custom permission sets programmatically—or use a permission set file, or define a ClickOnce application manifest with the permission set required by their application.

The CLR assigns each assembly its permissions when the assembly is loaded. Assemblies are granted these permissions based on some form of evidence substantiating their identity. There are origin-based evidences that examine where the assembly is loaded from (for example, all code coming from the Global Assembly Cache, or GAC, is granted full trust), or content-based evidence that examines some aspect of the assembly itself, such as its strong name.

Each app domain is always assigned a permission set called the app domain security policy, and any assembly loaded into that app domain is restricted to that permission set; otherwise it encounters a security exception. New app domains are launched with the FullTrust permission set, and since all code originating from the local machine also gets FullTrust by default, most .NET-based applications just work out of the box, in effect not utilizing CAS at all. This renders the code (and the user, the data, the machine, and even the network) susceptible to a variety of maladies, from security attacks such as viruses or worms, to plain user mistakes.

Code that is executing with less than full trust is called partially trusted code. Whenever any piece of managed code tries to access a resource or perform any operation using the .NET Framework (including interoperability with unmanaged code), the .NET Framework verifies that the assembly containing that code has the required permissions to perform the operation. If that assembly lacks a demanded permission, the .NET Framework throws a security exception thus aborting the operation.

Since a trusted assembly can be lured by a malicious, less-trusted assembly into performing operations that the less-trusted assemblies does not have permissions to execute, it is insufficient to demand the permissions only of the assembly performing an operation. Therefore, the .NET Framework walks the entire stack of callers, verifying that every caller up the stack has the required permissions. This stack walk is called a security demand, and it is performed regardless of the executing assembly's permissions.

Your code can also assert a permission—that is, declare that every caller up the stack has the demanded permissions. A permission assertion has the effect of stopping a stack walk. Your code can only assert permissions it already has, and it additionally requires the special security assertion permission.

It is always a good idea when asserting one permission to demand another in its place. Developers can demand or assert permissions programmatically using dedicated permission classes or use a matching set of attributes. Developers can also actively refuse permissions at the assembly, class, or method level. Refusing permissions or permitting only the limited set of permissions required by the code to execute reduces the surface area for a luring attack. For more on code access security, see Chapter 12 in my book, Programming .NET Components 2nd Edition, where I devote more than 100 pages to this fundamental technology and its applications.

Client-Side CAS

In the .NET Framework 3.5, WCF only allows a limited set of scenarios to execute in partial trust. WCF allows only the HTTP bindings BasicHttpBinding, WSHttpBinding, and WebHttpBinding (with the exclusion of the WSDualHttpBinding) to be called under partial trust and only with no security at all or with transport security. Furthermore, in the case of the WSHttpBinding, aspects such as message security, reliable messaging, and transactions are disallowed. All partial trust-enabled bindings must use text encoding. The client cannot use additional WCF facilities such as diagnostics. To enable usage in a partially trusted environment, the System.ServiceModel assembly allows for partial trust callers by including the AllowPartiallyTrustedCallers attribute as part of the assembly definition:

[assembly: AllowPartiallyTrustedCallers]

In the first release of WCF, omitting this attribute precluded all partial-trust use. In the .NET Framework 3.5, enforcing the limited set of supported features is now the responsibility of the bindings. Each non-HTTP binding actively demands full trust of its callers, be it the client proxy or the service host. The allowed HTTP bindings themselves do not demand full trust, but instead demand permissions according to the context of use. On the client side, these bindings demand permission to execute (security permission with execution flag), and permission to connect to the service (Web permission with connect flag to the target URI).

Beyond these demands on the client there are additional limitations on configuration. For example, the config file cannot contain any reference to any certificate store (for client-side certificate credentials) since touching the certificate store will cause WCF to demand full trust.

Ideally, you would like to tap into the full power of WCF from distributed transactions to reliable calls to various security credential types to intranet (or even same-machine) application communication over TCP and inter-process communication (IPC) channels such as named pipes, and do all that without trading off CAS—that is, without resorting to full trust.

Partially Trusted Clients

To enable clients at any partial-trust level to use any WCF feature and binding, you need to block the demand of the bindings for full trust. The only way to do that is to have the proxy itself assert full trust. Asserting full trust can be done via the PermissionSetAttribute using the Assert flag of the SecurityAction enum and specifying the type-safe string "FullTrust" for the permission name:

[PermissionSet(SecurityAction.Assert,Name = "FullTrust")]

Though the permission name is specified using a string, there is a degree of safety added by the compiler in that it verifies the allowed values.

In addition, you must prevent the client from directly accessing any method of the base class of ClientBase<T> (which still demands full trust), so the proxy needs to hide the commonly used methods of Close and Dispose. Having the proxy class itself access methods or properties of ClientBase<T> (such as Channel or constructors) is fine since the proxy asserts full trust.

The problem is that in order to assert full trust, the proxy itself must be granted full trust, something the partially trusted client is not able to provide in the first place. Consequently, you need to factor out the proxy class to its own assembly, mark it as public, and grant that assembly full trust. You can accomplish this by using the .NET Framework 2.0 Configuration control panel applet—simply identify the proxy's assembly using some content-based evidence such as its strong name and grant the assembly full trust.

You can also install the proxy assembly in the client's GAC. Since all assemblies coming from the GAC are granted full trust, the proxy will also gain full trust. You also need to remember to declare the AllowPartiallyTrustedCallers attribute; this will allow partially trusted callers to call the assembly.

Finally, you need to add the definition of the contract used by the proxy to the proxy's assembly (and mark the contract as public as well). This is required because WCF demands full trust of all assemblies up the call chain, and if the contract comes from a partially trusted assembly, the demand will fail. Figure 1 shows examples of these contract and proxy definitions.

Figure 1 Asserting Full Trust by the Proxy

[assembly: AllowPartiallyTrustedCallers]
 
[ServiceContract]
public interface IMyContract
{
  [OperationContract]
  void MyMethod();
}

[PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
public class MyContractClient :
  ClientBase<IMyContract>,IMyContract,IDisposable
{
  public MyContractClient() {}

  public MyContractClient(string endpointName) : base(endpointName) {}

  /* More constructors */ 

  public void MyMethod() {
    Channel.MyMethod();
  }
  public new void Close() {
    base.Close();
  }
  void IDisposable.Dispose() {
    Close();
  }
}

Client-Side Demands

Unfortunately, the technique showed in Figure 1 presents a potential security breach. By suppressing the security demands of WCF, any partially trusted client can now call any WCF service. Imagine a client that was not granted permissions connecting to a TCP socket or a Web site. While that client cannot use the network directly, it can bypass that limitation by calling out from the restricted client environment over WCF.

The solution for that problem is to use a dedicated subclass of ClientBase<T> that on the one hand will assert the blank WCF demand for full trust, and on the other hand will demand the appropriate specific security permissions according to what the client is trying to do. Such a proxy class is my PartialTrustClientBase<T> class, shown in Figure 2.

Figure 2 PartialTrustClientBase<T> Class

public abstract class PartialTrustClientBase<T> : 
  ClientBase<T>,IDisposable 
  where T : class
{
  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase() {}

  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase(string endpointName) : 
    base(endpointName) {}

  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  public PartialTrustClientBase(Binding binding,
    EndpointAddress remoteAddress) : 
    base(binding,remoteAddress) {}

  //Useful only for clients that want full-brunt raw demands from WCF
  protected new T Channel
  {
    [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
    get {
      return base.Channel;
    }
  }
  
  [PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
  new public void Close() {
    base.Close();
  }
  void IDisposable.Dispose() {
    Close();
  }

  protected object Invoke(string operation,params object[] args) {
    if(IsAsyncCall(operation)) {
      DemandAsyncPermissions();
    }
    DemandSyncPermissions(operation);
    CodeAccessSecurityHelper.PermissionSetFromStandardSet(
      StandardPermissionSet.FullTrust).Assert();

    Type contract = typeof(T);
    MethodInfo methodInfo = contract.GetMethod(operation);
    return methodInfo.Invoke(Channel,args);
  }

  protected virtual void DemandAsyncPermissions() {
    CodeAccessSecurityHelper.DemandAsyncPermissions();
  }

  protected virtual void DemandSyncPermissions(string operationName) {
    this.DemandClientPermissions(operation);
  }

  bool IsAsyncCall(string operation) {
    if(operation.StartsWith("Begin")) {
      MethodInfo info = typeof(T).GetMethod(operation);
      object[] attributes = info.GetCustomAttributes(
        typeof(OperationContractAttribute),false);
      Debug.Assert(attributes.Length == 1);
      return (attributes[0] as 
        OperationContractAttribute).AsyncPattern;
    }
    return false;
  }
}

PartialTrustClientBase<T> is used just like the regular proxy base class. You still need to grant full trust to the proxy class derived from it and allow partial-trust callers. However, unlike Figure 1, PartialTrustClientBase<T> does not assert full trust at the class level. Instead, it asserts full trust locally, just when required. In addition, PartialTrustClientBase<T> may also be used to demand other CAS permissions.

If you derive your proxy class from PartialTrustClientBase<T> and have the proxy assert full trust as shown here, then no demands will be made on the calling client:

[PermissionSet(SecurityAction.Assert,Name = "FullTrust")]
public class MyContractClient : 
  PartialTrustClientBase<IMyContract>,IMyContract
{
  public MyContractClient() {}

  public MyContractClient(string endpointName) : 
    base(endpointName) {}

  public void MyMethod() {
    Channel.MyMethod();
  }
}

The only difference between this code and Figure 1 is the new version is cleaner since the hiding of Close and Dispose is now done by PartialTrustClientBase<T>. This new proxy still suppresses all security demands by WCF and leaves the partially trusted client exposed to a luring attack or enables that partially trusted client to do more than intended.

Raw WCF Demands

The more security-conscious use of PartialTrustClientBase<T> is to not have the proxy assert full trust:

public class MyContractClient : 
  PartialTrustClientBase<IMyContract>,IMyContract
{
  public MyContractClient() {}
  public MyContractClient(string endpointName) : 
    base(endpointName) {}
  public void MyMethod() {
    Channel.MyMethod();
  }
}

To support such use, PartialTrustClientBase<T> surgically asserts full trust on its constructors and its Close method. In addition, PartialTrustClientBase<T> hides the Channel property of ClientBase<T> and asserts full trust on the get accessor. This is sufficient to suppress the WCF binding demand for full trust, since that demand is made when constructing the proxy, and when opening and closing its channel—but not when actually using it. The interesting effect of structuring the proxy this way is that now the client code will be subjected to the raw WCF security demands—that is, all the security demands required to marshal the call to the service!

For example, if the proxy is using the TCP binding, the proxy will first demand the client permission to execute (all managed code requires that permission). Second, the proxy will demand that the client have permission to connect to the required port on the service machine, and unrestricted DNS permissions (required to resolve the host's address). Third, there are some collateral permission demands unrelated to the use of TCP, pertaining to the context of the call.

If the client wishes to use Windows security and send the user's interactive identity, then the proxy will demand environment permission access to the USERNAME variable. If the client wishes to send alternative Windows credentials, then the proxy will demand security permission to control the principal. If the client wants to dispatch the call asynchronously or receive duplex callbacks, then the proxy will demand permissions to control the policy and the evidence (both are flags of the security permission, required when bouncing calls between threads). If the client wishes to use reliable messaging, then the proxy will demand policy control as well. If the client uses message security with user-name credentials, with service certificate negotiation and without validating the negotiated service certificate, then the proxy will also demand permission to control the policy and the evidence. If the client utilizes the WCF diagnostics and tracing facility, then the proxy will demand access to the COMPUTERNAME environment variable (to be able to trace it) and unmanaged code access (presumably to access the log files, so it should have been a file I/O permission instead).

Finally, the proxy will also demand of the client permission to execute unmanaged code. Unmanaged code access is a highly privileged security permission, granted only to the most trustworthy code. Granting unmanaged code access permission can amount to disabling CAS since unmanaged code is exempted from CAS. Classes and frameworks designed to work in a partial trust environment should never demand unmanaged code access (even if they use interop) and instead demand a more narrow permission describing the nature of the unmanaged operation performed. The TCP channel demands unmanaged code simply because its original design did not take into account partially trusted clients.

Then there are certain WCF capabilities that bluntly resort to full trust demands, even though there are perfectly matching permissions types. Any attempt to propagate a transaction requires full trust (instead using the distributed transaction permission) and any access of a certificate store requires full trust (instead of using the certificate store permission). Figure 3 shows the raw WCF security demands invoked by code such as my last revision of PartialTrustClientBase<T>, when the bindings are set to their default settings, for a few key scenarios such as transactions, reliability, diagnostics, asynchronous calls, certificate store access, and message security.

Figure 3 Raw WCF Client-Side Security Demands

Scenario Permissions
TCP Security permission with execution and unmanaged code, unrestricted DNS, socket permission to connect to port on target host
IPC Security permission with execution, unmanaged code, control policy, and control evidence
WS and WS Dual Security permission with execution and unmanaged code, Web permission to connect to URI
Basic and Web Security permission with execution, Web permission to connect to URI
MSMQ Security permission with execution and unmanaged code
Asynchronous calls, Duplex over TCP Security permission to control policy and evidence
RM over TCP Security permission to control policy
Windows security with interactive user credentials Environment permission to read USERNAME
Windows security with alternative credentials Security permission to control principal, Environment permission to read USERNAME
Diagnostic tracing Security permission with unmanaged code, Environment permission to read COMPUTERNAME
User-name credentials, Message security with service cert negotiation and without service cert validation Security permission to control policy and evidence, Store permission to enumerate certificates
User-name credentials, TCP message security with service cert negotiation and without service certificate validation Security permission to control policy and evidence
Any certificate store access, Transaction propagation Full trust
User-name credentials, Message security without service certificate negotiation or with service certificate validation, Certificate credentials Full trust

The only bindings that do not demand unmanaged code access are the basic and Web bindings. The WS binding defaults to message security by default, resulting in an unmanaged code access permission demand.

Structured Demands with PartialTrustClientBase<T>

As you can see from Figure 3, key aspects of WCF such as transactions, reliable messaging, unlimited message security interaction, and certificate store access all require full trust, thus rendering my prior version of PartialTrustClientBase<T> pointless in a partial-trust environment. Furthermore, demanding unmanaged code access by virtually all non-HTTP bindings (and the WS binding with message security) is unacceptable, negating the very idea of CAS for a partial-trust client.

To enable appropriate, secure, and correct use of WCF by a partially trusted client, PartialTrustClientBase<T> offers the Invoke method defined as:

protected object Invoke(string operation,params object[] args);

Invoke accepts the name of the operation to invoke and its parameters in the form of a comma-separated params array of objects. Rather than using the Channel property for invoking the call, Invoke uses reflection. Here is a proxy deriving from PartialTrustClientBase<T> using the Invoke method:

public class MyContractClient : 
  PartialTrustClientBase&lt;IMyContract&gt;,IMyContract 
{
  public MyContractClient() {}
  public MyContractClient(string endpointName) : 
    base(endpointName) {}
  public void MyMethod() {
    Invoke("MyMethod");
  }
}

Invoke will first demand the appropriate CAS permissions according to the scenario of the calling client and the target service endpoint. If the client is granted those permissions—that is, no security exception was raised by the demands—Invoke will programmatically assert full trust and proceed to invoke the operation, satisfied that the client has the right permissions to call the service. I call such behavior a structured permission demand.

Invoke cannot use an attribute to declaratively assert full trust, since that will mask any more granular permission it demands. Instead, the implementation of Invoke in Figure 2 first checks whether the call is invoked asynchronously (using the AsyncPattern flag of the operation contract). If it is, Invoke demands the appropriate permissions using the DemandAsyncPermissions helper method. Invoke then demands the synchronous permissions using the DemandSyncPermissions helper method. For the call itself, Invoke programmatically asserts full trust using my CodeAccessSecurityHelper class shown in Figure 4.

Figure 4 CodeAccessSecurityHelper Class

public enum StandardPermissionSet {
  Internet,
  LocalIntranet,
  FullTrust,
  Execution,
  SkipVerification
}

public static class CodeAccessSecurityHelper {
  public static PermissionSet PermissionSetFromStandardSet(
    StandardPermissionSet standardSet);
   
  public static void DemandClientPermissions<T>(this ClientBase<T> proxy) 
    where T : class;

  public static void DemandAsyncPermissions();
  
  //More members

The PermissionSetFromStandardSet method takes my enum value representing one of the standard .NET permission sets and returns the matching instance of PermissionSet (see Figure 5). PermissionSet, as its name implies, is a collection of permissions, but it can also represent the super permission set full trust (which is not really a set of individual permissions; it is more like a single permission). The PermissionSet class supports the IStackWalk interface, which lets you install a stack walk modifier, such as a modifier that stops the demand for the permissions in the permission set by asserting that all callers up the stack have those permissions. The stack walk modifier is removed automatically when the method that installed it returns. You can also explicitly remove it with the static RevertAssert method of PermissionSet.

Figure 5 PermissionState and PermissionSet

public enum StandardPermissionSet {
  Internet,
  LocalIntranet,
  FullTrust,
  Execution,
  SkipVerification
}

public static class CodeAccessSecurityHelper {
  public static PermissionSet PermissionSetFromStandardSet(
    StandardPermissionSet standardSet);
   
  public static void DemandClientPermissions<T>(this ClientBase<T> proxy) 
    where T : class;

  public static void DemandAsyncPermissions();
  
  //More members

 

Both the DemandAsyncPermissions and DemandSyncPermissions helper methods of PartialTrustClientBase<T> use corresponding methods on CodeAccessSecurityHelper to perform their demands.

The chart in Figure 6 shows the structured demands raised by PartialTrustClientBase<T>.Invoke as a function of the binding used and other aspects of the scenario such as the use of transactions, reliability, certificate store access, diagnostics, callbacks, and asynchronous calls.

Figure 6 Structured Security Demands of PartialTrustClientBase<T>

Scenario Permissions
TCP Security permission with execution, unrestricted DNS, Socket permission to connect to port on target host
IPC Security permission with execution, control policy, and control evidence
WS, Basic Security permission with execution and Web permission to connect to URI
WS-Dual Security permission with execution and Web permission to connect to URI, and Web permission to accept callbacks to callback address, minimal ASP.NET hosting permission
MSMQ Security permission with execution, MSMQ permission to send to queue
RM over TCP Security permission to control policy
Duplex over TCP, Asynchronous calls (AsyncPattern), User-name credentials, Message security with service certificate negotiation and without service certificate validation Security permission to control policy and control evidence
Windows security with interactive user credentials Environment permission to read USERNAME
Windows security with alternative credentials Security permission to control principal
Transaction propagation Unrestricted distributed transaction permission
User-name credentials, Message security without service cert negotiation or with service cert validation, Certificate credentials Store permission to enumerate stores, open store, and enumerate certificates
Diagnostic tracing Environment permission to read COMPUTERNAME, File I/O permission to path discovery, append, write to log files

Analyzing the Demands of Invoke

I based the structured demands on a few elements. First, whenever possible, I tried to approximate the raw demands on the client raised by WCF. That said, I did smooth the rough edges of WCF since it was not designed for comprehensive partial-trust use. None of the bindings and scenarios listed in Figure 6 demand full trust or unmanaged code access. There are plenty of places in the .NET Framework that were designed for use in a partial-trust environment in a similar context, and I relied on the same demands as those. Finally, in the other cases, to compensate for suppressing the full trust demands, I used experience, familiarity with CAS, and common sense to map WCF activities to demands for dedicated permission types.

When the WS-Dual binding is used, Invoke demands Web permission to connect to the target endpoint, as with any other HTTP binding. However, to allow for hosting the callback object it also demands minimal ASP.NET hosting permission and Web permission to accept the calls to the callback address. When the MSMQ binding is used, Invoke demands MSMQ permission to send messages to the target queue.

With any attempt to propagate the client's transaction to a service, Invoke demands unrestricted distributed transaction permission. In this case, a transaction-aware binding is used, the transaction flow is enabled in the binding, the transaction flow at the operation level is allowed, and the client has an ambient transaction.

Any attempt by the proxy to access the certificate store triggers demands for permission to enumerate the certificate stores, to open a store, and to enumerate the certificates in a store. This will happen when the client uses certificate credentials, or when message security is used and the client needs to validate the negotiated service certificate, or when the client does not negotiate a certificate and instead just loads a certificate to use for securing the message.

When the client uses WCF diagnostics, Invoke demands environment permission to read the computer name and file I/O permission for the log and trace files used.

Implementing Client-Side Structured Demands

As mentioned already, the demands are carried out by CodeAccessSecurityHelper, whose partial implementation is shown in Figure 7. All permission types in the .NET Framework support the IPermission interface:

public interface IPermission : ...
{
   void Demand();
   //More members 
}

 

Figure 7 Implementing CodeAccessSecurityHelper (Partial)

public static class CodeAccessSecurityHelper
{
  public static void DemandClientPermissions<T>(this ClientBase<T> proxy, 
    string operationName) where T : class
  {
    DemandClientConnectionPermissions(proxy.Endpoint);
    DemandTransactionPermissions(proxy.Endpoint,operationName);
    DemandTracingPermissions();
    DemandClientSecurityPermissions(proxy);
    DemandEnvironmentPermissions(proxy);
    DemandClientStorePermissions(proxy.Endpoint);
  }

  internal static void DemandClientConnectionPermissions(
    ServiceEndpoint endpoint)
  {
    PermissionSet connectionSet = new PermissionSet(PermissionState.None);

    if(endpoint.Binding is NetTcpBinding)
    {
      connectionSet.AddPermission(new SocketPermission(
        NetworkAccess.Connect,TransportType.Tcp,
        endpoint.Address.Uri.Host,endpoint.Address.Uri.Port));
         
      connectionSet.AddPermission(new DnsPermission(
        PermissionState.Unrestricted));
    }

    /* Rest of the bindings */ 

    connectionSet.Demand();
  }

  internal static void DemandTransactionPermissions(
    ServiceEndpoint endpoint)
  {
    DemandTransactionPermissions(endpoint,null);
  }

  internal static void DemandTransactionPermissions(
    ServiceEndpoint endpoint, string operationName)
  {
    bool transactionFlow = false;
    bool flowOptionAllowed = false;

    if(endpoint.Binding is NetTcpBinding)
    {
      NetTcpBinding tcpBinding = endpoint.Binding as NetTcpBinding;
      transactionFlow = tcpBinding.TransactionFlow;
    }

    /* Checking other bindings */ 

    if(transactionFlow)
    {
      if(Transaction.Current != null)
      {
        //If operationName is null then at least one operation 
        //needs to allow flow to trigger demand
        foreach(OperationDescription operation in 
          endpoint.Contract.Operations)
        {
          string name = operationName ?? operation.Name;
          if(name != operation.Name)
          {
            continue;
          }
          foreach(IOperationBehavior behavior in operation.Behaviors)
          {
            if(behavior is TransactionFlowAttribute)
            {
              TransactionFlowAttribute attribute = 
                behavior as TransactionFlowAttribute;
              if(attribute.Transactions != 
                TransactionFlowOption.NotAllowed)
              {
                flowOptionAllowed = true;
                break;
              }
            }
          }
          if(flowOptionAllowed)
          {
            break;
          }
        }
        if(flowOptionAllowed)
        {
          IPermission distributedTransactionPermission = 
            new DistributedTransactionPermission(
            PermissionState.Unrestricted);
          distributedTransactionPermission.Demand();
        }
      }
    }
  }
  //Rest of the implementation
}

Demanding any permission is done by instantiating the permission object and calling its implementation of the Demand method. When constructing a permission set, you can add individual permissions to it and then call Demand on the permission set to demand all permissions in the set.

The extension method DemandClientPermissions of CodeAccessSecurityHelper does the bulk of the demands on behalf of PartialTrustClientBase<T> (using an extension enables using it with any proxy class). It has a series of helper methods, all demanding permissions for their respective aspect. Figure 7 shows the code for DemandClientConnectionPermissions, which is used to demand connectivity permissions according to the binding. It examines the binding type used by the proxy and adds the appropriate permissions to a permission set object. It then calls Demand on the permission set.

The DemandTransactionPermissions method first verifies that the proxy is using a binding capable of transaction flow. If so, it verifies that the calling client actually has an ambient transaction to propagate (Transaction.Current is not null). If so, it scans the collection of operations for the endpoint's contract looking for the operation currently invoked. When the operation is found, DemandTransactionPermissions retrieves that operation's collection of operation behaviors. DemandTransactionPermissions examines each behavior, looking for the TransactionFlowAttribute. If the attribute is configured to allow transaction propagation, then DemandTransactionPermissions demands the distributed transaction permission. In a similar manner, DemandClientPermissions uses other helper methods to demand the appropriate permissions.

Finally, to enable partially trusted clients and callbacks, I defined the class PartialTrustDuplexClientBase<T,C>, and implemented it very much like PartialTrustClientBase<T>, one exception being that it adds the duplex support for clients receiving callbacks.

So that's a quick run through code access security in WCF, along with my solution for enabling partially trusted clients with appropriate levels of code-level permission. My next installment will demonstrate partially trusted services and partially trusted hosts. You will also get to see some advanced programming techniques for WCF and the .NET Framework.

Send your questions and comments to mmnet30@microsoft.com.

Juval Lowy is a software architect with IDesign providing WCF training and architecture consulting. He is also the Microsoft Regional Director for the Silicon Valley. His recent book is Programming WCF Services. Contact Juval at www.idesign.net.