WCF – BEA Aqualogic Interop Issue

There are always constraints when it comes to interoperability between .NET and Java platforms. I had to go through a 3 week long struggle in making a simple thing work on these platforms.

Here is the requirement,

Develop a WCF client which should talk to a Java Web Service running on Aqua Logic Web Server. The service is secured by 2 Way HTTPS (both Server & Client Certs) and message signing for non-repudiation.

Immediately after you see this requirement, anyone would just advice “TransportWithMessageCredentail” security mode which is out of the box as I did. I precisely did the same but wouldn’t succeed. Why?

The reason is simple. “TransportWithMessageCredential” by default signs the “timestamp” element on the SOAP Header and sends it across. It is designed in this way because, the timestamp is the smallest attribute and signing it takes lesser cycles of canonicalization, compared to any other element in the entire SOAP content. But, ALSB (AquaLogic Service Bus) wouldn’t recognize this request. It was always throwing an error saying,

No id attribute on element http://schemas.xmlsoap.org/soap/envelope/:Body

This means that ALSB requires the Body to be signed, and nothing else.

There is no way to address this interop issue with not only the out-of-box “TransportWithMessageCredentail” security mode but also with any other custom configuration as well.

But there is always a way to make things work in some or the other way. Here I show you how to make it work with a small modification on the service side.

In my above said requirement, the Request is signed (SOAP Body), but not the Response. With the following configuration, you can make WCF sign the request (body) and still use transport security.

<customBinding>
<binding name="SigningBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="MutualCertificate" requireDerivedKeys="false"
includeTimestamp="false" keyEntropyMode="ClientEntropy"
messageProtectionOrder="SignBeforeEncrypt"
messageSecurityVersion="WSSecurity10WSTrustFebruary2005WSSecureConversation

February2005WSSecurityPolicy11BasicSecurityProfile10"
requireSecurityContextCancellation="false" securityHeaderLayout="Strict" allowSerializedSigningTokenOnReply="true">
<secureConversationBootstrap />
<localClientSettings detectReplays="false"/>
</security>
<httpsTransport requireClientCertificate="true"/>
</binding>
</customBinding>

But the catch here is, WCF expects the response also to be signed as it signs the request. It necessarily asks you to have the server certificate as well, installed on the client machine which is accessing the service.

If you have the freedom to make the service behave so, you are out of trouble.

Below is the rest of the configuration..

<endpoint address=https://domain.com/services/service
               behaviorConfiguration="ServiceSecurityBehavior" binding="customBinding"
bindingConfiguration="SigningBinding" contract="MyContract"
name="SuscribeEventEndPoint">
<identity>
<certificateReference storeLocation="LocalMachine" x509FindType="FindByThumbprint"
findValue="v2d43d464abd384b5cc3a2d669862807241234567" />
</identity>
</endpoint>

<behaviors>
<endpointBehaviors>
<behavior name="ServiceSecurityBehavior">
<clientCredentials>
<clientCertificate findValue="123459f47cb80f67tgb385ae0ebc0b92f8861234"
storeLocation="LocalMachine" x509FindType="FindByThumbprint"/>
<serviceCertificate>
<defaultCertificate findValue="v2d43d464abd384b5cc3a2d669862807241234567"
storeLocation="LocalMachine" x509FindType="FindByThumbprint"/>

              </serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>