BizTalk ... WCF ... ProtectionLevel - a joust to the death (Part 2) - A world apart from the everday ...

A world apart from the everday ...

Assert.IsTrue(Entries.Count == 0);

BizTalk ... WCF ... ProtectionLevel - a joust to the death (Part 2)

In my previous post (Part 1) I introduced the problem and the fact that there didn’t appear to be a known solution out there … oh how we love a challenge!

Considering I was running into all sorts of dead-ends on the BizTalk side of things we switched all our services to run with EncryptAndSign, for now, just so that we could continue with development and functional testing.

We however wanted to be able to cater for changing the ProtectionLevel of the Service Contract on a deployment by deployment basis. The way it stands now, if you want to change your service from EncryptAndSign to say just Sign or None, you would have to change edit the actual service, rebuild and redeploy. Not ideal!

With loads and loads of Googling around we soon discovered that this kind of thing can be done through code ….

   1: var endpointAddress = new EndpointAddress(
   2:     new Uri(endPoint), 
   3:     EndpointIdentity.CreateDnsIdentity("Operator A"), 
   4:     (AddressHeaderCollection) null);
   5:  
   6: ChannelFactory<IHelloWorldService> factory = new ChannelFactory<IHelloWorldService>(
   7:     GetNewBindingForSecurity(), endpointAddress);
   8:  
   9: factory.Endpoint.Behaviors.Add(
  10:     new MessageProtectionBehavior() { Level = ProtectionLevel.Sign }
  11: );
  12:  
  13: factory.Credentials.ClientCertificate.SetCertificate(
  14:     StoreLocation.CurrentUser, 
  15:     StoreName.My, 
  16:     X509FindType.FindBySubjectName, 
  17:     "Operator A");
  18:  
  19: factory.Credentials.ServiceCertificate.SetDefaultCertificate(
  20:     StoreLocation.CurrentUser, 
  21:     StoreName.My, 
  22:     X509FindType.FindBySubjectName, 
  23:     "Operator A");
  24:  
  25: factory.Open();

So WCF is supposed to be extensible right …. RIGHT! If it can be done through code, and WCF is extensible then perhaps we have our solution!

Enter … custom endpoint behaviors.

This post helped me and put us on the right path; http://www.winterdom.com/weblog/2006/10/02/CustomWCFBehaviorsThroughAppConfig.aspx

So, we set out and built ourselves a quick custom endpoint that simply put, applies the ProtectionLevel of the service at runtime and exposes the ProtectionLevels as an enum that can now be configured in the web.config and the client’s app.config.

   1: public class MessageProtectionBehavior : IEndpointBehavior
   2: {
   3:     /// <summary>
   4:     ///   Gets or Set the level of message protection.
   5:     /// </summary>
   6:     /// <value>
   7:     ///   One of <see cref="ProtectionLevel"/> enumeration values (None, Sign or SignAndEncrypt).
   8:     /// </value>
   9:     public ProtectionLevel Level { get; set; }
  10:     
  11:     #region IEndpointBehavior Members
  12:     
  13:     public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection parameters)
  14:     {
  15:        endpoint.Contract.ProtectionLevel = Level;
  16:     
  17:        parameters.Remove<ChannelProtectionRequirements>();
  18:        var requirements = new ChannelProtectionRequirements();
  19:        parameters.Add(requirements);
  20:     
  21:        MessagePartSpecification unprotectedBody = new MessagePartSpecification();
  22:        MessagePartSpecification protectedBody = new MessagePartSpecification(true);
  23:        switch (Level)
  24:        {
  25:           case ProtectionLevel.None:
  26:              requirements.OutgoingSignatureParts.AddParts(unprotectedBody, "*");
  27:              requirements.IncomingSignatureParts.AddParts(unprotectedBody, "*");
  28:              requirements.OutgoingEncryptionParts.AddParts(unprotectedBody, "*");
  29:              requirements.IncomingEncryptionParts.AddParts(unprotectedBody, "*");
  30:              break;
  31:     
  32:           case ProtectionLevel.Sign:
  33:              requirements.OutgoingSignatureParts.AddParts(protectedBody, "*");
  34:              requirements.IncomingSignatureParts.AddParts(protectedBody, "*");
  35:              requirements.OutgoingEncryptionParts.AddParts(unprotectedBody, "*");
  36:              requirements.IncomingEncryptionParts.AddParts(unprotectedBody, "*");
  37:              break;
  38:     
  39:           case ProtectionLevel.EncryptAndSign:
  40:              requirements.OutgoingSignatureParts.AddParts(protectedBody, "*");
  41:              requirements.IncomingSignatureParts.AddParts(protectedBody, "*");
  42:              requirements.OutgoingEncryptionParts.AddParts(protectedBody, "*");
  43:              requirements.IncomingEncryptionParts.AddParts(protectedBody, "*");
  44:              break;
  45:        }    
  46:     }
  47:     

The magic happens on lines 9 where we expose our custom “Level” property and then on line 15 we set the ProtectionLevel of the Contract which was the piece we’ve been needing to do.

We have effectively (and successfully) extended the standard WCF behaviour.

Once we had this, the rest was easy …

http://msdn.microsoft.com/en-us/library/cc952299.aspx

A bit bummed out that we have to place this in the machine.config though; I tried in my application’s config file and even in the BTSNTSvc.exe.config but it doesn’t pick it up anymore; it seems it has to be the machine.config.

Once this behaviour was registered in the machine.config we could get at it in the configuration of the WCF-Custom adapter.

WCF-Custom add behavior extensions

WCF-Custom picking custom ProtectionLevel 

Switching the behaviour in our service to Sign, and matching this setting in the BizTalk configuration everything worked!

Checking the output of the WCF diagnostics log files I can confirm that the message is signed, and that the body of the message is in clear text.

Switching to EncryptAndSign, WCF Diagnostics logs clearly shows the expected result; the message is signed as before, but this time the body part is encrypted.

Switching to None, well yup you guessed it …. still works!

Now BizTalk and WCF and ProtectionLevel can play nicely together!

What a relief!

Posted: Dec 08 2008, 06:09 PM by Ryan CrawCour | with no comments
Filed under:
Leave a Comment

(required) 

(required) 

(optional)

(required) 


Enter the numbers above: