Securing Custom Headers, Version 1

I'm securing messages using SOAP security but I also have some message headers that are generated dynamically at runtime. How do I protect the generated message headers as well?

If you've used SOAP security, then you've probably done it by decorating your messages with attributes that describe what the protection level is for various message parts. Obviously there's a problem here trying to take that approach with dynamically generated message headers. Since these message headers aren't a part of the declared message, there's nothing in the contract that you can decorate. We're going to look at two ways of solving this problem. For both articles, I'm only going to talk about protecting messages by signing. It is trivially easy to add encryption in if you want. The same is true for protecting headers on incoming versus outgoing messages as well.

The first approach we're going to look at is to modify the security settings through binding parameters. The binding parameters contain the protection requirements of the contract. The protection requirements contain the list of headers. That gives us a two-step approach to accessing the list of headers. Since we need to change the protection requirements before the service is started, we'll insert a contract behavior to make the adjustments.

 public class SignMessageHeaderBehavior : Attribute, IContractBehavior
{
   string action;
   string header;
   string ns;

   public SignMessageHeaderBehavior(string header, string ns, string action)
   {
      this.header = header;
      this.ns = ns;
      this.action = action;
   }

   public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
   {
      ChannelProtectionRequirements requirements = bindingParameters.Find<ChannelProtectionRequirements>();
      XmlQualifiedName qName = new XmlQualifiedName(header, ns);
      MessagePartSpecification part = new MessagePartSpecification(qName);
      requirements.OutgoingSignatureParts.AddParts(part, action);
   }

   public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
   {
   }

   public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
   {
   }

   public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
   {
   }
}

Now, you've got a behavior that can at run time add a new message header to the list of signed headers. The action distinguishes which of the operations that you're talking about for that particular contract. Does this solution work? Yes. Is this the best solution? Maybe not. One issue that you may find troubling is that the behavior approach is too late to add the message header to the service description. If anyone looks at the WSDL, then they won't see the header, although if both the client and server are coordinated then this can work. Next time we'll look at a different approach that fixes this.

Next time: Securing Custom Headers, Version 2