In a recent implementation, I was building a WCF intermediary which receives messages and does some processing and then route these messages to a set of services that are not under my control.
One of the requirements, was that in specific cases I had to edit the incoming Security header and set misunderstand to 0 instead of 1. As I said, I have no control over the destination services, therefore I cannot use the ValidateMustUndestand service behavior nor the fine grained UnderstoodHeaders property of the message headers to bypass validation at these services.
So in the intermediary I built an inspector which intercepts the message just before being sent to the destination services. It then removes the incoming Security header after it preserves the content, then creates a custom header with mustunderstand set to false, then injects this header instead of the old one.
Here is the header definition:
public class SecurityHeader:MessageHeader { private const string HeaderName = “Security”; private const string HeaderNamespace = “http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”; private bool mustUnderstand;private string content; public override string Name { get { return HeaderName; } }public override string Namespace { get { return HeaderNamespace; } }public override bool MustUnderstand { get { return mustUnderstand; } } public SecurityHeader(string content, bool mustUnderstand) protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion) writer.WriteRaw(this.content); } |
The OnWriteStartHeader overridden method allows us to have fine-grained control over the how the Security element itself will look like. Here I do the changes I want.
The OnWriteHeaderContents overridden method gives us control over the content of the header. Here I just use the WriteRaw method of the writer to write the same content I preserved before. You can get this content in the inspector using request.ToString() from inside the inspector’s BeforeSendRequest method, and then do some manipulation to get the contents inside the Security header. Alternatively you can an XmlReader or XmlDictionaryReader to parse the message and get the required content.
Inside the inspector, you can use the following code to first remove the original security header, then add the one with the updated header:
request.Headers.RemoveAll(“Security”, “http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”);
SecurityHeader head = new SecurityHeader(content, false); |
Hi,
Thanks for taking the time to post this approach.
I too have a similiar issue with the MustUnderstand attribute. Although I would like to remove the attribute altogether. Java services have an issue with this apparently.
You suggested above that the Security header could be extracted from the Request.ToString and the Security content could then be used in the constructor of the new SecurityHeader. However the Security header doesn’t seem to appear in the Headers collection. How are you manipulating the contents of the security header please? Am I missing something?
Thanks,
Rik
Hi,
When you say ‘the security header doesn’t seem to appear in the headers collection’, when do you mean exactly? can you see the header in fiddler for example? or is the header not part of the traffic at all?
Hi Mohamad,
According to the Microsoft documentation, the security header is not yet generated at the Message inspector level. This occurs at the Transport channel. If you need to intercept the message you have to create a Message Encoder to be able to edit the security header.
Hence my question how are you able to gain access to the security header to edit it? I have created an Encoder to remove the MustUnderstand attribute but the Encoder is removing the Security header before posting. This is a separate issue. Removing the MustUnderstand attribute appears to be a common problem with no definite solution anywhere.
Your solution, if I could get it to work would be cleaner and would allow me to to edit the security header. But that’s the problem, I can’t see the Security Header to edit it.
Hope that makes sense.
Best regards,
Rik
well you’re right. i should’ve noticed that in your previous post.
that is why in this blog post if you notice i’m talking about a router inspector, rather than the standard WCF message inspector. what this means is that i have a separate service, with a generic untyped interface that catches raw SOAP messages. this way i get access to all headers.
you could follow the same approach to solve your issue. the disadvantage of course is an extra call..
if you would like help implementing such router, i can send you the code
Hi Mohamad,
Thanks for the reply. I hadn’t appreciated you were using a router inspector. It makes sense to me now.
I would be grateful if you could supply some example code of your approach.
Thanks for your help.
Rik
Here is the router code. You can add the code that manipulates the header inside the corresponding process message method.
https://1drv.ms/u/s!Athnq7Tlw-8UiSQxPvn2z0NDhlVy
If you want in depth discussion about routing, you can check my pluralsight course on SOA, it has a detailed module.
Thanks very much. I’ll take a look.
It was your Pluralsight courses that led me to your blog. I have found the courses very useful and informative for the current project I am involved with.
Thanks again.
Rik