Recently I had to connect o a WebSphere service using BizTalk. The service required a client cetificate for transport authentication but also a username/password in the soap envelope. Ok, this might be considered as overdoing the security, both requirements authenticating the client, but it did not sound too strange to me and I thought BizTalk with WCF would probably handle that out of the box without any problems.
Well.. turned out I was wrong and it wasn’t an easy nut to crack for me so I’ll blog it for the masses.
First, this was a service that supported SOAP version 1.1, also known as BasicHTTP for WCF people. This offers you the following security types:
Type | Descriptions |
None | Anonymous, so no no security and no authentication |
Transport | Transport level authentication provider. Comparable to the IIS settings, eabling you to set None (no authentication), Basic, Digest, Ntlm, Windows or Certificate (encryption) authentication. This option requires that you use HTTPS. |
Message | Enables Authenticaton in the SOAP header. Offers using a username / password or certificate (signing), In this case, the certificae will be used as a signature over the the soap message and not for transport level encryption. Because this option is for HTTP transport only, WCF does not permi the usage of the usernam/passowrd option. |
TransportWithMessageCredential | A combination of Transport options and Message options, but does not offer to set a client certificte for transport. So basically this offers you to use a username/password or a certificate (signing) in the message. This enables Transport level security so it requires usage of the HTTPS protocol |
TransportCredentialOnly | Similar to Transport, but allows you to send unencrypted passwords over HTTP. Good for testing without certificates, but not meant for production purposes. |
Basically, these are the samen options you use when using WCF in a C# project. In theory, you would use Transport with Message Credential, but the BizTalk Interface does not give you the opportunity to use a client certificate..

So what if we would do this in a ‘normal’ c# project? I created the service proxy and edited the app.config like this:
inside the binding:
<security mode="TransportWithMessageCredential">
<transport clientcredentialtype="Certificate" proxycredentialtype="None" realm="">
<message clientcredentialtype="UserName" algorithmsuite="Default" />
</transport>
</security>
the client definition references a my credential behavior:
<client>
<endpoint
address="https://mysite.com/myservice"
behaviorconfiguration="CredentialBehavior"
binding="basicHttpBinding"
bindingconfiguration="myserviceHttpBinding"
contract="mysite.myservice"
name="myserviceHttpPort">
</endpoint>
</client>
The behavior selects the right certificate
<behaviors>
<endpointbehaviors>
<behavior name="credentialbehavior">
<clientcredentials>
<clientcertificate
findvalue="f3f4b10b819a4c1b3e54ba8b8e1f888d75e4fb23"
x509findtype="FindByThumbprint"
storelocation="LocalMachine"
storename="My" />
</clientcredentials>
</behavior>
</endpointbehaviors>
</behaviors>
Because in a C# project you cannot specify the user credentials in the config file, you need to specify these in code:
client.ClientCredentials.UserName.UserName = "Logica";
client.ClientCredentials.UserName.Password = "itsme";
Unfortunately this did not work. Even when explicitly specified, WCF does not want to send the certificate. Finally, a search with BING on TransportWithMessageCredential BasicHttpBinding clientcertificate led me to this post:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/45df57f0-e010-43ef-92f6-ed06c247d733/
So it’s not just me.. it’s official.
With the solution already being there, I tried it out. One more hiccup was solved quick using another search, and now I both ‘forced’ WCF to send the client certificate while suppressing the timestamp. For this, some custom code is needed:
// code to set RequireClientCertificate to True
// also set IncludeTimestamp to false
// necessary to enable client certificates over BasicHttpBinding.
ServiceProxy.serviceClient client;
client = new ServiceProxy.dw_serviceClient();
System.ServiceModel.Channels.Binding bbinding =
(System.ServiceModel.Channels.Binding)client.Endpoint.Binding;
BindingElementCollection bec = bbinding.CreateBindingElements();
TransportSecurityBindingElement tsp = bec.Find();
tsp.IncludeTimestamp = false;
HttpsTransportBindingElement httpsBinding = bec.Find();
TextMessageEncodingBindingElement encoding = bec.Find();
httpsBinding.RequireClientCertificate = true;
CustomBinding binding = new CustomBinding(tsp, encoding, httpsBinding);
client.Endpoint.Binding = binding;
Now this worked in WCF using a ‘normal’ C# project and some custom code. But this being a BizTalk solution, I needed to be able specify this all in configuration. The regular way to do this, is by using a custom behavior in WCF.
A custom behavior is not that hard to create. You just create a new c# project, with a main class (I named “SendClientCertificateBehavior”) that derives from both System.Attribute and System.ServiceModel.Description.IEndpointBehavior. Use the right mouse button to implement the interface and add the code to the “ApplyClientBehavior” behavior (in this case). Use the endpoint as provided in the method parameters.
Also, you need to define the configuration element by creating another class that derives from System.ServiceModel.Configuration.BehaviorExtensionElement. I added that class in the same C# file. The two methods of this class refer to the first class.:
public override Type BehaviorType
{
get
{
return typeof(SendClientCertificateBehavior);
}
}
protected override object CreateBehavior()
{
return new SendClientCertificateBehavior();
}
To work in BizTalk, this assembly needs to be signed, and put into the GAC. Then, in machine.config file you need to add a line for the new Behavior in the section :
Now, for using plain old c#, you add ‘SendClientCertificate’ to the behavior in the the app.config:
<behaviors>
<endpointbehaviors>
<behavior name="CustomBehavior">
<clientcredentials>
<clientcertificate
findvalue="F3F4B10B819A4C1B3E54BA8B8E1F888D75E4FB23"
x509findtype="FindByThumbprint"
storelocation="LocalMachine"
storename="My" />
</clientcredentials>
<sendclientcertificate/>
</behavior>
</endpointbehaviors>
</behaviors>
In BizTalk, you have to use a WCF-Custom port. These ports come with no settings applied, so you have to select some stuff yourself:
First enter the url of your service. Then specify BasicHTTPBinding. In the binding, specify the securitymode as ‘TransportWithMessageCredential’. After that you have to add the behaviors in the “Behavior” tab. Right click on ‘endpointBehavior’ and add both the clientCredentials behavior and the sendClientCertificate behavior we created ourself:

Under ‘clientcredentials’ we can add the certificate information, in my case a thumbprint of a certificate that is in the CurrentUser section.
In the credentials tab, you can then add username and password.
So.. in the end it IS fully configurable. Just needs a lot of work up front.