Monday, January 5, 2009

Signing custom headers in WCF

@YaronNaveh

Recently I had an interesting case with WCF "raw message" contract:


public interface IUniversalContract
{
  [OperationContract(Action = "*", ReplyAction = "*")]
  Message ProcessMessage(Message message);
}


The message I used on the client side contained some SOAP headers. Since this is an untyped message these headers were neither encrypted nor signed. That was a show stopper for me.

I saw this blog post by Nicholas Allen and immediatelly tried the following syntax:


ChannelProtectionRequirements requirements = bindingParameters.Find();
XmlQualifiedName qName = new XmlQualifiedName(header, ns);
MessagePartSpecification part = new MessagePartSpecification(qName);
requirements.OutgoingSignatureParts.AddParts(part, action);


However the request message was still not being encrypted nor signed. I struggled with this issue for some time until I was lucky enough to find Pedro Felix's message in the WCF MSDN forum:


The MSDN docs state that

a) IncomingSignatureParts - Gets a collection of message parts that are signed for messages from client to server

b) OutgoingSignatureParts - Gets a collection of message parts that are signed for messages from server to client


In other words the OutgoingSignatureParts always relates to server outgoing messages while client outgoing stuff is always considered as "incoming". After fixing this the code worked like a charm. I probably should have proactively RTFM myself but at least I felt good for not being the only one who fell for this...

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

4 comments:

Diego Gonzalez said...

Hi Yaron,

Do you know if the Timestamp element of the Security header could be encrypted with this method?

I'm trying something like this, but it does not seem to work.

XmlQualifiedName qName = new XmlQualifiedName("Timestamp", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
MessagePartSpecification timestampHeader = new MessagePartSpecification(qName);
MessagePartSpecification body = new MessagePartSpecification(true);

requirements.OutgoingEncryptionParts.AddParts(timestampHeader, "*");
requirements.OutgoingEncryptionParts.AddParts(body, "*");

DiegoG,

Yaron Naveh (MVP) said...

I don't think the timestamp should be ever encrypted. The reason is that the server should know if the message is valid or not even before processing the encryption - do prevent DOS attacks. Why do you need to encrypt it?

Diego Gonzalez said...

Because I'm calling a WebService in Java which has such setting and is mandatory. However do you know if there is a way of doing this?

DiegoG

Yaron Naveh (MVP) said...

I don't know if it can be done out of the box. You may need to use .Net encryption API to manually do it.