Configuring Protection Level

Is it possible to configure the protection level for message parts at runtime?

Only certain configurations make doing this particularly easy. When using transport security with Windows credentials, the WindowsStreamSecurityBindingElement allows you to directly set the protection level (changing the protection level when using SSL doesn't make as much sense due to the way SSL works). On the other hand, there's no equivalent facility for message security, which will always give you both encryption and signing if you haven't explicitly set the protection level on the contract.

There are a few ways to attack this lack of configurability:

1.
configure a custom service host to override the contract description during ApplyConfiguration
2.
configure a behavior to modify the contract description when behaviors are applied
3.
configure a behavior to modify the channel protection requirements when the security channel is instantiated

The first approach is a very indiscriminate way to get the job done. Modifying the entire service is almost certainly not what you want to do, so you'd need some way to describe the scope of specific message parts that you want to modify. Behaviors can be much more targeted.

The second approach has the hidden downside that modifying the contract description at one endpoint can potentially (depending on order of execution) modify the contract description for other endpoints. This also is almost certainly not what you want to do.

Finally, both the second and third approaches have downsides due to being implemented with behaviors. User behaviors are executed after the security validation behavior that is run as part of the service start up. This means that you're unable to declare a protection level on the contract and then later reduce it in the behavior unless the binding is capable of supporting the originally specified protection level. Also, the results of modifying a contract in a behavior don't get reflected in metadata, which makes a variety of tasks harder.

In short, none of these options are particularly good. The third approach is probably the most workable although it does suffer a number of downsides. You can base this approach on the following bit of code.

 public class ProtectionLevelEndpointBehavior : IEndpointBehavior
{
   public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
   {
      ChannelProtectionRequirements requirements = bindingParameters.Find<ChannelProtectionRequirements>();
      // reconfigure the requirements that are being passed down
   }

   public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
   {
   }

   public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
   {
   }

   public void Validate(ServiceEndpoint endpoint)
   {
   }
}

However, I'd recommend trying to avoid this sort of dynamic protection level configuration if possible.

Next time: MIX Video Wrap Up