In the previous article, Part One, we looked at how to modify a response from a non-WCF service to conform to what WCF expects using a custom text message encoder. In this part, we examine how to use another custom text message encoder to modify the security header of a WCF message to be interoperable with a non-WCF service.
This code is developed using the .NET Framework 4.0, Windows Communication Foundation (WCF). Following the service login described in Part One, the client is configured with a custom binding. Note below that UserNameOverTransport is used as the security authentication mode. This allows WCF to create a security section containing a Username token.
<binding name="InSession">
<customTextMessageEncoding messageType="InSession" messageVersion="Soap11"
encoding="utf-8" />
<security allowSerializedSigningTokenOnReply="false" enableUnsecuredResponse="true"
authenticationMode="UserNameOverTransport" securityHeaderLayout="Strict"
includeTimestamp="true" messageSecurityVersion="WSSecurity10WSTrustFebruary2005..."
requireSignatureConfirmation="false">
<localClientSettingsblue;"> detectReplays="false" reconnectTransportOnFailure="true" />
<secureConversationBootstrap />
</security>
<httpsTransport keepAliveEnabled="false" requireClientCertificate="false" />
</binding>
The request Security header elem
ent needs to contain three tokens:
1. Timestamp
2. UsernameToken
3. SAML Assertion
Since the authentication mode is UserNameOverTransport, the Username token is created when WCF creates the message. The security section also specifies includeTimestamp="true", so the timestamp token is included in the message security section. All that is left is for the custom message encoder, customTextMessageEncoding messageType="InSession", to add the SAML assertion to the message. Again, an custom text message encoder is created as described in the MSDN sample http://msdn.microsoft.com/en-us/library/ms751486(v=VS.90).aspx. The WriteMessage method is modified to insert the SAML token:
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();
// get the persisted SAML Assertion and add to the stream representation of the message
stream.Position = 0;
XElement xmlMessage = XElement.Load(stream);
XElement samlXml = XElement.Load("saml.xml");
XNamespace sec = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";
xmlMessage.Descendants(sec + "Security").First().Add(samlXml);
stream.Position = 0;
xmlMessage.Save(stream);
xmlMessage.Save("request.xml");
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;
}
The WCF request has now been modified to deliver what the non-WCF service is expecting in the request.
In Part 1 of this article, http://www.falconwebtech.com/post/2010/04/01/WCF-Interoperability-and-Extensibility-Part-One.aspx, we looked at how to modify a response from a non-WCF service to conform to what WCF expects using a custom text message encoder. In this part, we examined how to use another custom text message encoder to modify the security header of a WCF message to be interoperable with a non-WCF service. In the final section, Part 3, we’ll look at how to use a custom message inspector to further modify WCF messages for non-WCF service interoperability.