Custom WCF MessageHeader – Set MustUnderstand

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)
{
this.content = content;
this.mustUnderstand = mustUnderstand;
}

protected override void OnWriteHeaderContents(XmlDictionaryWriter writer, MessageVersion messageVersion)
{

writer.WriteRaw(this.content);
}
protected override void OnWriteStartHeader(XmlDictionaryWriter writer, MessageVersion messageVersion)
{
writer.WriteStartElement(“o”, “Security”, “http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd”);
if (this.mustUnderstand)
writer.WriteAttributeString(“s:mustUnderstand”, “1”);

}
}

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);
request.Headers.Add(head);

Advertisements

7 thoughts on “Custom WCF MessageHeader – Set MustUnderstand

  1. Rik

    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

    Reply
    1. mohamadhalabi Post author

      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?

      Reply
      1. Rik

        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

  2. mohamadhalabi Post author

    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

    Reply
    1. Rik

      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

      Reply
    1. Rik

      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

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s