Removing the SOAP mustUnderstand attribute from a WCF message
I’ve been working on an integration to an endpoint that’s been under development. Furthermore the service is special in that the endpoint I hit acts as a forwarding gateway to an internal endpoint. This had implications for the security configuration of the service. A new release meant that my configured UsernameToken WS-Security binding stopped working. I suspect it was denied by the gateway but I’m not entirely sure. Either way the error message suggested that it had something to do with a SOAP mustUnderstand attribute not being understood. This blog post details how you can apply a fix that’ll allow you to get through.
The SOAP mustUnderstand attribute says that the recipient must understand and obey the semantics of the SOAP header to which it is applied, or fail processing the message.
Investigating the messages going across the wire I found that the mustUnderstand attribute was only applied to the WS-Security header. It makes sense that you want the security configuration to be obeyed by the recipient, otherwise there wouldn’t be any point in sending it over. The service though failed to process it. I had an equivalent call working through SoapUI, the reason being that SoapUI can be configured to omit the mustUnderstand attribute. Hence I knew that if I could remove the mustUnderstand attribute from my WCF call I’d have end-to-end connection.
However, removing that is not so easy! Out of the box WCF doesn’t allow you to remove this by simply flipping a switch. It makes a lot of sense, but doesn’t really help me much.
WCF is very extensible. Actually to the point where it’s so extensible that it can be tough to figure out where to hook in. To remove the mustUnderstand attribute from the Security header you need to hook into the pipeline where the header is about to be applied or just after it’s been applied. One place to do that is with a Custom Message Encoder. Microsoft has a sample Message Encoder that adds character set and media type to a text encoder. Based on this sample I wrote some code that looks at the message before it’s being written on the wire and alters the XML.
You want to hook into the WriteMessage method of the Message Encoder. In here you can read the message into XLINQ and manipulate it.
public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
{
MemoryStream stream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(stream, this.writerSettings);
message.WriteMessage(writer);
writer.Close();
stream.Position = 0;
//Interesting part
XNamespace soapEnvelope = "http://schemas.xmlsoap.org/soap/envelope/";
Namespace sec = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
var securityHeader = xmlMessage.Descendants(sec + "Security");
var attribute = securityHeader.Attributes(soapEnvelope + "mustUnderstand").First();
if (attribute != null)
attribute.Remove();
//End Interesting part
stream.Position = 0;
xmlMessage.Save(stream);
byte[] messageBytes = stream.GetBuffer();
int messageLength = (int)stream.Position;
stream.Close();
int totalLength = messageLength + messageOffset;
byte[] totalBytes = bufferManager.TakeBuffer(totalLength);
Array.Copy(messageBytes, 0, totalBytes, messageOffset, messageLength);
ArraySegment<byte> byteArray = new ArraySegment<byte>(totalBytes, messageOffset, messageLength);
return byteArray;
I’ve included the full method for reference, but the main thing is between the “Interesting part” comments. First we define some namespaces that we’ll use to locate the Security header and mustUnderstand attribute. Then we extract the Security header element and look for the XML mustUnderstand attribute identified in the SOAP envelope namespace. We remove the attribute. The full code base then continues by writing the modified XML message to the stream being returned by WCF.
If you’re using the sample from Microsoft there’s an error in the app.config that adds the Custom Message Encoder. The full element needs to look like this:
<extensions>
<bindingElementExtensions>
<add name="customTextMessageEncoding" type="Microsoft.Samples.CustomTextMessageEncoder.CustomTextMessageEncodingElement, TestApplication"/>
</bindingElementExtensions>
</extensions>
In the sample documentation the class in the type-attribute is wrongly put down as CustomTextMessageEncodingBindingSection and it needs to be CustomTextMessageEncodingElement as shown above.
You exchange the Text Message Encoder with this new Custom Encoder and it’ll remove the mustUnderstand attribute from the SOAP header. Setting this up on a custom binding is seen below:
<customTextMessageEncoding messageVersion="Soap11" mediaType="text/xml" />
instead of
<textMessageEncoding messageVersion="Soap11" />
With this in place my WCF client could now talk to the service endpoint again. Later the gateway service was fixed so it didn’t break when a Security-header with mustUnderstand was sent to it. However this example serves to show that you can modify the message going across the wire in a lot of ways. You have access to the full XML, and hence can do whatever is required. Be careful though when dealing with the Security aspects of WCF, especially when you have timestamps, signatures, and encryption involved. It only takes a single character to invalidate a signature, and hence you want to be careful where and what you change.
If you like my writing you should subscribe to my RSS feed.
Leave a Reply
You must be logged in to post a comment.
I am a self employed independent software development consultant at